
var COMMONS = {
	version: 1.24,
	/**
	 * Identifies the browser and the operation system.
	 * @type boolean
	 */
	userAgent: navigator.userAgent.toLowerCase()
};

/**
 * The flag indicates that the browser is MS Internet Explorer.
 * @type boolean
 */
COMMONS.isIE = COMMONS.userAgent.indexOf('msie') > -1;
/**
 * The flag indicates that the browser is Opera.
 * @type boolean
 */
COMMONS.isOpera = COMMONS.userAgent.indexOf('opera') > -1;
/**
 * The flag indicates that the browser is Safari.
 * @type boolean
 */
COMMONS.isSafari = (!COMMONS.isOpera && COMMONS.userAgent.indexOf('safari') > -1);
/**
 * The flag indicates that the browser is Gecko Firefox.
 * @type boolean
 */
COMMONS.isGecko = (!COMMONS.isOpera && !COMMONS.isSafari && COMMONS.userAgent.indexOf('gecko') > -1);
/**
 * The flag indicates that the  operation system is MS Windows.
 * @type boolean
 */
COMMONS.isWin32 = (COMMONS.userAgent.indexOf('windows') > -1);
/**
 * The flag indicates that the  operation system is MAC OS.
 * @type boolean
 */
COMMONS.isMacOs = (COMMONS.userAgent.indexOf('mac') > -1);

/**
 * The function which returns false.
 * @return {Boolean} Returns false.
 */
COMMONS.returnFalse = function returnFalse()
{
	return false;
};

/**
 * The function which returns true.
 * @return {Boolean} Returns true.
 */
COMMONS.returnTrue = function returnTrue()
{
	return true;
};

/**
 * The proxy function which itself returns argument.
 * @return Returns the himself argument.
 */
COMMONS.proxy = function(aValue)
{
	return aValue;
};

/**
 * Indicates that the argument is an object.
 * @return {Boolean} If so it returns true, otherwise it returns false.
 *
 * @param The value is to be checked.
 */
COMMONS.isObject = function(anObject)
{
	return anObject !== null && typeof(anObject) === "object";
};

/**
 * Indicates that the argument is an array.
 * @return {Boolean} If so it returns true, otherwise it returns false.
 *
 * @param The value to be checked.
 */
COMMONS.isArray = function(anObject)
{
	return anObject instanceof Array;
};

/**
 * Indicates that the argument is a RegExp.
 * @return {Boolean} If so it returns true, otherwise it returns false.
 *
 * @param  The value to be checked.
 */
COMMONS.isRegExp = function(anObject)
{
	return anObject instanceof RegExp;
};

/**
 * Indicates that the argument is a Date.
 * @return {Boolean} If so it returns true, otherwise it returns false.
 *
 * @param  The value to be checked.
 */
COMMONS.isDate = function(anObject)
{
	return anObject instanceof  Date;
};

/**
 * Indicates that the argument is a Number.
 * @return {Boolean} If so it returns true, otherwise it returns false.
 *
 * @param  The value is to be checked.
 */
COMMONS.isNumber = function(anObject)
{
	return typeof(anObject) === "number";
};

/**
 * Indicates that the argument is a Boolean.
 * @return {Boolean} If so it returns true, otherwise it returns false.
 *
 * @param  The value to be checked.
 */
COMMONS.isBoolean = function(anObject)
{
	return typeof(anObject) === "boolean";
};

/**
 * Indicates that the argument is a String.
 * @return {Boolean} If so it returns true, otherwise it returns false.
 *
 * @param The value is to be checked.
 */
COMMONS.isString = function(anObject)
{
	return typeof(anObject) === "string";
};

/**
 * Indicates that the argument is a function.
 * @return {Boolean} If so it returns true, otherwise it returns false.
 *
 * @param The value to be checked.
 */
COMMONS.isFunction = function(anObject)
{
	return typeof(anObject) === "function";
};

/**
 * Indicates that the argument is undefined.
 * @return {Boolean} If so it returns true, otherwise it returns false.
 *
 * @param The value to be checked.
 */
COMMONS.isUndefined = function(anObject)
{
	return anObject === undefined;
};

/**
 * Indicates that the argument is not null and not undefined.
 * @return {Boolean} If so it returns true, otherwise it returns false.
 *
 * @param The value is to be checked.
 */
COMMONS.isDefined = function(anObject)
{
	return anObject !== null && anObject !== undefined;
};

/**
 * Parses the string argument to an integer.
 * @return {Number} Returns the integer represented by the string argument in the 10 radix.
 *
 * @param {String} The string containing the integer representation, which is 
 * to be parsed as number or a number.
 */
COMMONS.toInteger = function(aValue)
{
	var result = 0;
	if (aValue)
	{
		result = this.isNumber(aValue) ? aValue : parseInt(aValue, 10);
	}
	return result;
};

/**
 * Parses the string argument to a float.
 * @return {Number} Returns the number represented by the string argument.
 *
 * @param {String} The string containing the number representation, which is
 * to be parsed as number or a number.
 */
COMMONS.toFloat = function(aValue)
{
	var result = 0;
	if (aValue)
	{
		result = this.isNumber(aValue) ? aValue : parseFloat(aValue);
	}
	return result;
};

/**
 * The predefined string representations of boolean "true" value.
 * <ul>
 *  <li>true
 *  <li>yes
 *  <li>ok
 * </ul>
 * @type Map
 */
COMMONS.BOOLEAN_TRUE = {"true":true, "yes":true, "ok":true};

/**
 * Parses the string argument to a boolean.
 * @return {Boolean} Returns the boolean represented by the string argument.
 *
 * @param {String} The string containing the boolean representation,which is to be
 * compared with predefined values or boolean.
 *
 * @see #BOOLEAN_TRUE
 */
COMMONS.toBoolean = function(aValue)
{
	var result = false;
	if (aValue)
	{
		result = this.isBoolean(aValue) ? aValue : this.BOOLEAN_TRUE[ aValue.toString().toLowerCase() ];
	}
	return result;
};

/**
 * A Logger object is used to collect log events for a specific system or components.
 * @constructor
 * Each log events has a message part and category associated with it.
 * The Logger's methods designed to logging severe error allowed to associate
 * log event with occured Error and error called method.
 * The Logger output method can be overriden subject to custom project architecture.
 *
 * @param {String} The logger prefix.
 */
function Logger(aPrefix)
{
	/**
	 * The logger prefix used to identify logged class.
	 * @type String
	 */
	this.fPrefix = aPrefix;
}

/**
 * The TRACE logging category designates fine-grained
 * informational events than the DEBUG category.
 */
Logger.TRACE = 20;

/**
 * The DEBUG logging category designates fine-grained
 * informational events that are the most useful for debugging the
 * application.
 */
Logger.DEBUG = 50;

/**
 * The INFO logging category designates informational messages
 * that illustrate the progress of the application at coarse-grained
 * level.
 */
Logger.INFO = 70;

/**
 * The WARN logging category designates potentially
 * harmful situations.
 */
Logger.WARN = 80;

/**
 * The ERROR logging category designates error events that
 * may allow the application to continue running.
 */
Logger.ERROR = 90;

/**
 * The FATAL logging category designates very severe error
 * that will presumably lead the application to abort.
 */
Logger.FATAL = 100;

/**
 * Logs event according to TRACE category.
 *
 * @param {String} The message to log.
 * @param {Exception} The exception to log.
 */
Logger.prototype.trace = function(aMessage, anException)
{
	this.log(Logger.TRACE, aMessage, anException);
};

/**
 * Logs event according to DEBUG category.
 *
 * @param {String} The message to log.
 * @param {Exception} The exception to log.
 */
Logger.prototype.debug = function(aMessage, anException)
{
	this.log(Logger.DEBUG, aMessage, anException);
};

/**
 * Logs event according to INFO category.
 *
 * @param {String} The message to log.
 * @param {Exception} The exception to log.
 */
Logger.prototype.info = function(aMessage, anException)
{
	this.log(Logger.INFO, aMessage, anException);
};

/**
 * Logs event according to WARN category.
 *
 * @param {String} The message to log.
 * @param {Exception} The exception to log.
 */
Logger.prototype.warning = function(aMessage, anException)
{
	this.log(Logger.WARN, aMessage, anException);
};

/**
 * Logs event according to ERROR category.
 *
 * @param {String} The message  to log.
 * @param {Exception} The exception to log.
 * @param {Function} The error called method.
 */
Logger.prototype.error = function(aMessage, anException, aMethod)
{
	this.log(Logger.ERROR, aMessage, anException, aMethod);
};

/**
 * Logs event according to FATAL category.
 *
 * @param {String} The message  to log.
 * @param {Exception} The exception to log.
 * @param {Function} The error called method.
 */
Logger.prototype.fatal = function(aMessage, anException, aMethod)
{
	this.log(Logger.FATAL, aMessage, anException, aMethod);
};

/**
 * Processes log event.
 *
 * @param {Integer} The log event category.
 * @param {String} The message to log.
 * @param {Exception} The exception to log.
 * @param {Function} The error called method.
 */
Logger.prototype.log = function(aType, aMessage, anException, aMethod)
{
	var txt = COMMONS.isDefined(this.fPrefix) ? "[" + this.fPrefix + "] " + aMessage : aMessage;
	if (COMMONS.isDefined(anException))
	{
		txt += ": " + anException.name + ", " + anException.message;
	}
	if (COMMONS.isDefined(aMethod))
	{
		txt += "\n" + aMethod.toString();
	}
	this.printLog(aType, txt);
};

/**
 * Prints the log message.
 *
 * @param {Integer} The log event category.
 * @param {String} The message to print.
 */
Logger.prototype.printLog = function(aType, aMessage)
{
	if (aType > Logger.WARN)
	{
		alert(aMessage);
	}
};

/**
 * Defines common logger.
 */
COMMONS.fLogger = new Logger("Common");

/**
 * Defines the JSINER (originated from JavaScript INheritance) is a lazy inheritance implementation
 * in JavaScript.
 * @constructor
 * <br><b>Lazy inheritance</b> is a design pattern used in JavaScript computer programming.
 * It designates a ?postponed linking? of an object with its prototype (class) until it is needed.
 * If used properly, such approach may increase efficiency, simplicity and flexibility of
 * OOP based code written using JavaScript.
 * Since lazy inheritance is called only for instance creation, it JSINER allowed to combine process
 * of class prototype creation with resolving necessary dependencies of that class.<br>
 *
 * The instances of objects in lazy inheritance are created in ?mixed? mode ? on first invocation,
 * a factory is used to modify class prototype which is later used to create subsequent object instances.<br>
 *
 * The main features of lazy inheritance approach are:
 * <ul>
 *  <li> Lazy inheritance is prototype-based inheritance;
 *  <li> Maintaining proper order of script files declaration is not obligatory;
 *  <li> HTML page loading is faster, since there is no need in creation objects
 *  during page initialization and, additionally, some scripts could be loaded only
 *  at the moment in which they are actually necessary;
 *  <li> The parent classes for the object can be loaded dynamically after defining the object type;
 *  <li> Dependencies are declared in more explicit way; it?s not necessary to group
 *  particular scripts into ?modules? artificially and define dependencies between such ?modules?;
 *  <li> If lazy mode of scripts loading is used, only important scripts (those which are highly
 *  necessary for application functionality) will be loaded.
 * </ul>
 * <br>
 * The following code illustrates <b>JSINER' lazy inheritance</b> usage case:<br>
 *
 * <pre>
 *  // Person constructor. The code defined in person.js.
 *  function Person(aName)
 *  {
 *    this.fName = aName;
 *  }
 *
 * // Returns the string representation of the Person.
 * Person.prototype.toString = function()
 * {
 *   return "Person: " + this.getName();
 * };
 *
 * // The code is defined in employee.js.
 * // Dependency declaration, defines that Employee required "person", no scripts are loaded so far
 * // The Employee class required "person" script to be loaded.
 * JSINER.addDependency( {Employee:"person"} );
 *
 * // Employee? constructor and inheritance definition.
 * // Actual instance of Person and loading all their dependencies
 * // will happen with first instantiation of the Employee.
 * function Employee(aName, aUID)
 * {
 *   var self = JSINER.extend(this, "Person"); // lazy inheritance calling
 *   self.fName = aName;
 *   self.fUID = aUID;
 *   return self;
 * }
 *
 * // Returns the string representation of the Employee.
 * Employee.prototype.toString = function()
 * {
 *   var person = Employee.superClass.toString.call(this);
 *    return this.fUID + ":" + person;
 * };
 * </code>
 */
//function JSINER() {}

/**
 * The JSINER' name space.
 * @private
 */
var JSINER = {
	/**
   * Defines the prefix used to prepare JavaScript URI.
   * @type String
   * @see #getScriptURI
   */
  scriptPrefix:"script/",
	/**
	 * Defines the suffix used to prepare JavaScript URI.
	 * @type String
	 * @see #getScriptURI
	 */
	scriptSuffix:".js",
	/**
	 * Defines the version used to prepare JavaScript URI.
	 * @type Number
	 * @see #getScriptURI
	 */
	version: 1.0
};

/**
 * Defines object dependencies structure.
 * <samp>{ Class1:["dependency1", "dependency2"], Class2:"dependency" }</samp>.
 */
JSINER.fDependency = {};

/**
 * Defines a class map for unknown classes.
 */
JSINER.fClassMap = {};

/**
 * Defines JSINER logger.
 */
JSINER.fLogger = new Logger("JSINER");

/**
 * Lookups the object constructor.
 *
 * @param The parameter which used to lookup an object constuctor.
 * Available parameter types:
 * <ul>
 * <li>The string that represented constructor name;
 * <li>The function that is the object constructor;
 * <li>The object that constuctor should be obtained.
 * </ul>
 *
 * @returns {Function} Returns the object constructor.
 */
JSINER.getConstructor = function(anObject)
{
	var result = null;
	if (COMMONS.isString(anObject))
	{
		result = window[anObject];
	}
	else
	if (COMMONS.isFunction(anObject))
	{
		result = anObject;
	}
	else
	if (COMMONS.isObject(anObject))
	{
		result = anObject.constructor;
	}
	return result;
};

/**
 * Computes an object type.
 *
 * @param The object to be introspected.
 * @return {String} Returns object type by object constructor if it defined
 * otherwise returns null.
 */
JSINER.getType = function(anObject)
{
	var result = (typeof anObject);
	if (COMMONS.isObject(anObject))
	{
		if ( COMMONS.isRegExp(anObject) )
		{
			result = "RegExp";
		}
		else
		{
			var constr = this.getConstructor(anObject);
			if (COMMONS.isDefined(constr))
			{
				var cons = constr.toString();
				var index = cons.indexOf('(');
				result = ((index > 0) ? cons.substring(cons.indexOf(' ') + 1, index) : cons);

				if ( this.fClassMap[result] !== undefined )
				{
					result = this.fClassMap[result];
				}
				else
				if ( window[result] === undefined )
				{
					for(var name in window)
					{
						if ( window[name] === constr )
						{
							this.fClassMap[result] = name;
							result = name;
							break;
						}
					}
				}
			}
		}
	}
	return result;
};

/**
 * Returns JavaScript URI by argument.
 * The method can be overridden subject to custom project structure.
 *
 * @param {String} The key, which is used to obtain the JavaScript URI.
 * @return {String} Returns the JavaScript URI.
 */
JSINER.getScriptURI = function(aURL)
{
	var result = null;
	if ( COMMONS.isString(aURL) )
	{
		result = this.scriptPrefix;
		if ( /js[i|o]ner/.test(aURL) )
		{
			result += aURL;
		}
		else
		{
		  result += aURL.replace(/[.]/g, '/');
		}
		result = Transporter.addParameter(result + this.scriptSuffix, "ver", this.version );
	}
	return result;
};

/**
  * Checks that the JavaScript is already loaded.
  *
  * The method can be overriden subject to custom project structure.
  * @return {Boolean} If so, it returns true, otherwise it returns false.
  *
  * @param {String} The key is used to obtain the JavaScript URI.
  */
JSINER.isScriptLoaded = function(aKey)
{
	var result = this.fScripts.isContains(aKey);
	if ( !result )
	{
		var uri = this.getScriptURI(aKey);
		var index = uri.indexOf('?');
		if ( index > 0 )
		{
			uri = uri.substring(0, index);
		}

		var scripts = document.getElementsByTagName("script");
		for (var i = 0; i < scripts.length; i++)
		{
			var src = scripts[i].src;
			if ( src.indexOf(uri) >= 0 )
			{
				result = true;
				break;
			}
		}
	}
	this.fLogger.info("The script [" + aKey + "] are " + (result ? "loaded" : "not loaded"));
	return result;
};

/**
 * Sets new collection of object dependencies, such as JSON structure.
 *
 * @param {JSON} The JSON representation of objects relations.
 * <samp>COMMONS.setDependency( { Class1:["dependency1", "dependency2"], Class2:"dependency" } );</samp>.
 * That designates   
 */
JSINER.setDependency = function(aJson)
{
	this.fDependency = COMMONS.isDefined(aJson) ? aJson : {};
};

/**
 * Adds the object dependecy.
 *
 * @param {JSON} The JSON representation of object dependency structure.
 * <samp>COMMONS.addDependency( { Class1:["dependency1", "dependency2"], Class2:"dependency" } );</samp>.
 */
JSINER.addDependency = function(aJson)
{
	if (COMMONS.isDefined(aJson))
	{
		for (var name in aJson)
		{
			var dependency = this.fDependency[name];
			if ( !COMMONS.isArray(dependency) )
			{
				this.fDependency[name] = [];
				dependency = this.fDependency[name];
			}

			var value = aJson[name];
			if ( COMMONS.isArray(value) )
			{
				for( var i=0; i < value.length; i++)
				{
					dependency.push( value[i] );
				}
			}
			else
			{
				dependency.push( value );
			}
		}
	}
};

/**
 * Returns the registered object dependency.
 *
 * @param The object.
 * @param The class from which the object inherit.
 * @return {Array} Returns the object dependency.
 *
 * @see #addDependency
 * @see #setDependency
 */
JSINER.getDependency = function(anObject, aClass)
{
	var type = this.getType(anObject);
	return this.fDependency[type];
};

/**
 * Creates the instance of the object by constructor and class from which to inherit.
 *
 * @param {Function} The object constructor.
 * @param {Function} The class from which to inherit.
 *
 * @return Returns instance of the object if class from which to inherit definded
 * otherwise returns null.
 */
JSINER.createInstance = function(aConstructor, aClass)
{
	var result = null;
	if (COMMONS.isFunction(aConstructor) && COMMONS.isFunction(aClass) && aClass !== Object)
	{
		var oldPrototype = aConstructor.prototype;        	// stores object prototype properties
		var oldToString = aConstructor.prototype.toString; 	// stores toString property for IE only

		aConstructor.prototype = new aClass(); 		          // overrides constuctor prototype
		aConstructor.prototype.constructor = aConstructor;	// restores class constructor
		aConstructor.superClass = aClass.prototype;         // adds superclass property

		for (var name in oldPrototype) //restores old prototype properties
		{
			aConstructor.prototype[name] = oldPrototype[name];
		}
		aConstructor.prototype.toString = oldToString;
		
		aConstructor.$extend = true; // sets flag that the class is already tied
		result = new aConstructor(); // creates new instance of the class
	}
	return result;
};

/**
 * Inherits the object by specified class.
 *
 * @param The processed object.
 * @param The class name or class from which to inherit.
 */
JSINER.extend = function(anObject, aClass)
{
	var doExtend = function(anObject, aClass)
	{
		var result = anObject;
		var cons = anObject.constructor;
		if ( COMMONS.isUndefined(cons.$extend) )
		{
			var dependency = this.getDependency(anObject, aClass);
			if ( COMMONS.isArray(dependency) )
			{
				var toolkit = this;
				this.inject(dependency, function()
				{
					var inheritClass = toolkit.getConstructor(aClass);
					result = toolkit.createInstance(cons, inheritClass) || result;
				});
			}
			else
			{
				var inheritClass = this.getConstructor(aClass);
				result = this.createInstance(cons, inheritClass) || result;
			}
		}
		return result;
	};

	var result = doExtend.call(this, anObject, aClass);
	var inheritClass = this.getConstructor(aClass);
	if ( COMMONS.isFunction(inheritClass) )
	{
		inheritClass.call(result);
	}
	return result;
};


/**
 * The interceptor type designates that the intercept method
 * should be called to process before the object method.
 */
JSINER.INTERCEPT_BEFORE = 0;

/**
 * The interceptor type designates that the intercept method
 * should be called to process after the object method.
 */
JSINER.INTERCEPT_AFTER = 1;

/**
 * The interceptor type designates that the intercept method
 * should be called to process instead the object method.
 */
JSINER.INTERCEPT_INSTEAD = 2;

/**
 * The interceptor type designates that the intercept method
 * should be called to process when in the object method
 * catch arises an exception.
 */
JSINER.INTERCEPT_ON_ERROR = 3;

/**
 * The map of class methods which are intercepted now.
 * @see #unregisterInterceptor
 */
JSINER.fMethods = new HashMap();

/**
 * Registers interceptor on defined method of the class
 * and all children of the class.
 *
 * @param The class of the objects.
 * @param {String} The method name.
 * @param {Integer} The interceptor type.
 * @param {Function} The method should be used to intercept class.
 */
JSINER.registerInterceptor = function(aClass, aMethodName, aType, aMethod)
{
	var constr = this.getConstructor(aClass);
	if (constr !== null && COMMONS.isFunction(aMethod))
	{
		var key = this.getType(constr) + "." + aMethodName;
		var oldMethod = constr.prototype[aMethodName];
		if (!this.fMethods.isContains(key))
		{
			this.fMethods.put(key, oldMethod);
		}
		if (this.isUndefined(oldMethod))
		{
			aType = this.INTERCEPT_INSTEAD;
		}

		var newFunction = null;
		switch (aType)
		{
			case this.INTERCEPT_BEFORE:
				newFunction = function()
				{
					aMethod.apply(this, arguments);
					return oldMethod.apply(this, arguments);
				};
				break;
			case this.INTERCEPT_AFTER:
				newFunction = function()
				{
					var result = oldMethod.apply(this, arguments);
					aMethod.apply(this, arguments);
					return result;
				};
				break;
			case this.INTERCEPT_INSTEAD:
				newFunction = function()
				{
					var result = aMethod.apply(this, arguments);
					return result;
				};
				break;
			case this.INTERCEPT_ON_ERROR:
				newFunction = function()
				{
					var result = null;
					try
					{
						result = oldMethod.apply(this, arguments);
					}
					catch(ex)
					{
						result = aMethod.apply(this, arguments);
					}
					return result;
				};
				break;
			default:
				this.fLogger.error("register interceptor, unsupported type " + aType);
				break;
		}
		constr.prototype[aMethodName] = newFunction;
	}
	else
	{
		this.fLogger.error("register interceptor, unsupported arguments " + aClass );
	}
};

/**
 * Unregisters the interceptor on defined method of the class.
 *
 * @param The class of the objects.
 * @param {String} The method name.
 */
JSINER.unregisterInterceptor = function(aClass, aMethodName)
{
	var constr = this.getConstructor(aClass);
	if (constr !== null)
	{
		var key = this.getType(constr) + "." + aMethodName;
		if (this.fMethods.isContains(key))
		{
			constr.prototype[aMethodName] = this.fMethods.get(key);
			this.fMethods.remove(key);
		}
		else
		{
			this.fLogger.warning("unregister interceptor, " + key + " never was registered.");
		}
	}
	else
	{
		this.fLogger.error("unregister interceptor, unable to obtain object constructor " + aClass);
	}
};

/**
 * Introspects object and creates string representation of object structure.
 *
 * @param {Object} The introspected object.
 * @param {Boolean} The flag defines that the object properties
 * should be not introspected.
 *
 * @return {String} The string representation of object stucture.
 */
JSINER.getInfo = function(anObject, anAttributesOnly)
{
	var result = typeof(anObject);
	if (COMMONS.isObject(anObject))
	{
		result += "[" + this.getType(anObject) + "]\n";
		if ( !anAttributesOnly )
		{
			var properties = [];
			var value;
			for (var name in anObject)
			{
				try
				{
					value = anObject[name];
					properties.push(COMMONS.isFunction(value) ? (name + "()") : (name + "=" + value));
				}
				catch(ex)
				{
					properties.push(name);
				}
			}
			if (properties.length > 0)
			{
				result += properties.sort().join(", ");
			}
		}

		if ( COMMONS.isArray(Object.attributes) )
		{
			var attributes = [];
			var attribute;
			try
			{
				for (var j = 0; j < anObject.attributes.length; j++)
				{
					attribute = anObject.attributes[j];
					if (attribute.nodeValue !== null && attribute.nodeValue !== '')
					{
						attributes.push(attribute.name + "=" + attribute.nodeValue);
					}
				}
			}
			catch(ex)
			{
			}
			if (attributes.length > 0)
			{
				result += "\n [" + attributes.sort().join(", ") + "]";
			}
		}
	}
	return result;
};

/**
 * A HashMap - an object that maps keys to values and does not contain duplicate keys.
 * @constructor
 *
 * @param {JSON} The object used to constructs the HashMap with the same
 * mappings as the specified by parameter property-value map.
 */
function HashMap(anObject)
{
	/**
	 * The map: key - value.
	 * @private
	 */
	this.fObject = anObject || {};
	/**
	 * The number of elements in the collection.
	 * @private
	 * @type Integer
	 */
	this.fSize = 0;
	for(var name in this.fObject )
	{
		if ( this.fObject.hasOwnProperty(name) )
		{
		  this.fSize++;
		}	
	}
}

/**
 * Indicates that the collection contains no elements.
 * @return {Boolean} Returns true if the collection contains no elements.
 */
HashMap.prototype.isEmpty = function()
{
	return this.getSize() === 0;
};

/**
 * Returns the number of elements in the collection.
 * @return {Integer} Returns the number of elements in the collection.
 */
HashMap.prototype.getSize = function()
{
	return this.fSize;
};

/**
 * Returns the value which the collection maps the specified key.
 * Returns undefined if the collection contains no mapping for this key.
 * @param {String} The key.
 * @return Returns the value according to which the collection maps the specified key.
 */
HashMap.prototype.get = function(aKey)
{
	return this.fObject[aKey];
};

/**
 * Indicates that the collection contains the specified key.
 * @param {String} The key, which presence in the collection is to be tested.
 * @return {Boolean} Returns true if the collection contains the specified key.
 */
HashMap.prototype.isContains = function(aKey)
{
	return COMMONS.isDefined(this.get(aKey));
};

/**
 * Associates the value with the specified key in this collection.
 * @param {String} The key.
 * @param  The value.
 */
HashMap.prototype.put = function(aKey, aValue)
{
	if (!this.isContains(aKey))
	{
		this.fSize++;
	}
	this.fObject[aKey] = aValue;
};

/**
 * Removes the specified key from the collection.
 * @param {String} The key to be removed from the collection.
 */
HashMap.prototype.remove = function(aKey)
{
  if ( this.isContains(aKey))
	{
		this.fObject[aKey] = undefined;
		delete this.fObject[aKey];

		if ( !this.isContains(aKey) )
		{
			this.fSize--;
		}
	}
};

/**
 * Clears the collection.
 */
HashMap.prototype.clear = function()
{
	this.fSize = 0;
	this.fObject = {};
};

/**
 * A KeySet - a collection of unique keys.
 * The KeySet inherits from HashMap.
 * @constuctor
 * 
 * @param The arguments which used to prepare a set by the specified values.
 */
function KeySet()
{
	var self = JSINER.extend(this, HashMap);
	for( var i = 0; i < arguments.length; i++ )
	{
		self.add(arguments[i]);
	}
	return self;
}

/**
 * Adds the specified key to the set.
 * @param {String} The key to be added to the set.
 */
KeySet.prototype.add = function(aKey)
{
	KeySet.superClass.put.call(this, aKey, true);
};


/**
 * Returns the number of elements in the collection.
 * @return {Integer} Returns the number of elements in the collection.
 */
KeySet.prototype.getSize = function()
{
	return this.fSize;
};

/**
 * Defines a set of already loaded scripts.
 */
JSINER.fScripts = new KeySet();

/**
  * Indicates that two objects are equal.
  * Limitation:
  * <ul>
  *  <li>cross links are not supported;
  *  <li>nodes are compared by ID.
  * </ul>
  *
  * @return {Boolean} Returns true if the objects are equal, false - otherwise.
  * @param The first object.
  * @param The second object.
  */
COMMONS.isEquals = function(anObject1, anObject2)
{
	function isObjectEquals(anObject1, anObject2)
	{
		var result = true;
		var set = new KeySet();
		for (var name in anObject1)
		{
			if (anObject1.hasOwnProperty(name))
			{
				if (!COMMONS.isEquals(anObject1[name], anObject2[name]))
				{
					result = false;
					break;
				}
				set.add(name);
			}
		}
		for (var name in anObject2)
		{
			if (anObject2.hasOwnProperty(name) && !set.isContains(name))
			{
				if (!COMMONS.isEquals(anObject1[name], anObject2[name]))
				{
					result = false;
					break;
				}
			}
		}
		return result
	}

	var result = JSINER.getType(anObject1) === JSINER.getType(anObject2);
	if ( result )
	{
		if (COMMONS.isObject(anObject1))
		{
			if ( !isNaN(anObject1.nodeType) )
			{
				result = COMMONS.isString(anObject1.id);
				if ( result )
				{
				  result = anObject1.nodeType === anObject2.nodeType &&
				           anObject1.nodeName === anObject2.nodeName &&
					 			   anObject1.id === anObject2.id;
				}
			}
			else
			{
				if (COMMONS.isArray(anObject1))
				{
					result = (anObject1.length === anObject2.length);
				}
				if (result)
				{
					result = isObjectEquals(anObject1, anObject2);
				}
			}
		}
		else
		{
			result = (anObject1 === anObject2);
		}
	}
	return result;
};

/**
 * An AJAX transporter.
 * Provides a interface to cross-browser instantiantion of the XMLHttpRequest. 
 * @constructor
 * The main feature of the AJAX transporter
 * is ability to register custom response handlers for
 * corresponding HTTP XML request statuses.
 * It allowed to use custom HTTP XML status codes to assign
 * custom particular business logic. For example: code 5222 can
 * designates that the server is busy and code 5223 - the session is expired.
 *
 * @param {Function} The method is invocated if data is loaded successfully.
 * @param {String} The transporter task ID.
 *
 * @param {String} The HTTP method, which is used for the request.
 * If the method is not defined, POST is used for sending data to server.
 * and GET is used for loading data from server.
 *
 * @param {Integer} The max count of attempts, which is used for sending data. 
 * The behavior of the transporter can be customized by custom response handlers.
 *
 * @param {Boolean} The flag determines whether XMLHttpRequest
 * is to be send the request asynchronously or not.
 */
function Transporter(anOnLoad, aTaskID, aMethod, aCounter, anAsynch)
{
	/**
	  * The flag determines whether XMLHttpRequest
    * is to be send the request asynchronously or not.
    * @type Boolean
	  */
	this.fAsynch = COMMONS.isBoolean(anAsynch) ? anAsynch : true;
	/**
	  * The transporter task ID.
	  * @type String
	  */
	this.fTaskID = aTaskID;
	/**
	  * The max count of attempts, which is used for sending data to URL.
	  * @type Integer
	  */
	this.fCounter = COMMONS.isNumber(aCounter) ? Math.max(aCounter, 0) : 1;
	/**
	  * The HTTP method, which is used for the request
	  * @type String
	  */
	this.fMethod = aMethod;
	/**
	  * The method is invocated if data is loaded successfully.
	  * @type Function
	  */
	this.onLoad = anOnLoad;

	/**
	  * The polling frequency, in milliseconds, to make next attemption to send request
	  * if result was failure.
	  * The behavior of the transporter can be customized by custom response handlers.
	  * @type Integer
	  * @see #setResponseHandeler
	  */
	this.fTimeout = 1000;
	/**
	  * The URI which used to send the request.
	  * @private
	  */
	this.fURI = null;
	/**
	  * The URL query part.
	  * @private
	  */
	this.fQueryString = null;
	/**
	  * The current request attemption counter.
	  * @private
	  */
	this.fTaskCounter = this.fCounter;
	/**
	  * The XMLHTTPRequest object.
	  * @private
	  */
	this.fReq = null;
	/**
	  * The send request task id.
	  * @private
	  */
	this.fReqTaskID = null;
	/**
	  * The map [reposnse staus - function] of response handlers.
	  * @see #setResponseHandeler
	  * @private
	  */
	this.fResponseHandlers = new HashMap();
	/**
	  * Registers default respponse handlers.
	  * @private
	  */
	this.registerDefaults();
}

/**
  * The set of transporter tasks ID.
  */
Transporter.fTaskSet = new KeySet();

/**
 * Sets the transporter task status.
 *
 * @param {String} The transporter task ID.
 * @param {Boolean} The transporter task status.
 * True represented that the task is alive, false - the contrary.
 */
Transporter.setTaskAlive = function(aTaskID, anAlive)
{
	if (COMMONS.isDefined(aTaskID))
	{
		if (anAlive)
		{
			Transporter.fTaskSet.add(aTaskID);
		}
		else
		{
			Transporter.fTaskSet.remove(aTaskID);
		}
	}
};

/**
 * Indicates the transporter overall status.
 *
 * @return {Boolean} Returns true if any of transporter tasks are alive,
 * otherwise it returns false.
 */
Transporter.isLoaderAlive = function(aTaskID)
{
	var result = !Transporter.fTaskSet.isEmpty();
	return result;
};

/**
 * Indicates the transporter task status.
 *
 * @param {String} The transporter task ID.
 * @return {Boolean} Returns true if the task is alive,
 * otherwise it returns false.
 */
Transporter.isTaskAlive = function(aTaskID)
{
	var result = false;
	if (COMMONS.isDefined(aTaskID))
	{
		result = Transporter.fTaskSet.isContains(aTaskID);
	}
	return result;
};

/**
 * Adds parameter to defined URL.
 * <ul>
 *  <li>In case when the URL does not contain query part: <code>URL?name=value</code>.
 *  <li>In case when the URL contains query part: <code>URL&name=value</code>.
 *  <li>In case when the URL query part contains the parameter, parameter value will be replaced.
 * </ul>
 *
 * @param {String} The URL.
 * @param {String} The parameter name.
 * @param {String} The parameter value.
 * @return {String} Returns the modified URL.
 */
Transporter.addParameter = function(aURL, aParamName, aValue)
{
	var result = aURL;
	if ( COMMONS.isString(aURL) && COMMONS.isString(aParamName) && COMMONS.isDefined(aValue) )
	{
		var prefix = aParamName + "=";
		var index = aURL.indexOf(prefix);
		if ( index > 0 )
		{
			result = aURL.substring(0, index + prefix.length) + aValue;
			var lastIndex = aURL.indexOf("&", index + prefix.length);
			if ( lastIndex > 0 )
			{
				result += aURL.substring(lastIndex, aURL.length);
			}
		}
		else
		{
			result += (result.indexOf('?') > 0) ? "&" : "?" ;
			result += prefix + aValue;
		}
	}
	return result;
};

/**
 * Predefined collection of ActiveX objects is used for creation of
 * XMLHttpRequest by Microsoft IE.
 */
Transporter.ActiveX_TRANSPORT = ["Msxml2.XMLHTTP", "Microsoft.XMLHTTP", "Msxml2.XMLHTTP.5.0",
																"Msxml2.XMLHTTP.4.0", "MSXML2.XMLHTTP.3.0"];


/**
 * Creates transporter logger.
 */
Transporter.prototype.fLogger = new Logger("Transporter");

/**
 * Returns HTTP request query string by set of data represented as order of name and value.
 *
 * @param  {Array} The array which contains the ordered request query parameters.
 * <samp>getQueryString( [0, 1, "param1", value1, "param2", value2], 2)</samp>
 * The second parameter 2 defines a start point from which
 * the query parameters start iterated in an array.
 * <samp>getQueryString( ["param1", value1, "param2", value2] )</samp>
 *
 * @return {Integer} The index in the array which used as start point to iterate the query parameters.
 * If the index is not defined, iterate starts from the fist element of the array.
 *
 * @return {String} Returns HTTP request query string.
 */
Transporter.prototype.getQueryString = function(anArray, aIndex)
{
	var result = null;
	var index = COMMONS.isNumber(aIndex) ? Math.max(aIndex, 0) : 0;
	if (COMMONS.isArray(anArray) && anArray.length >= index)
	{
		result = anArray[index];
		if (anArray.length >= index)
		{
			for (var i = index + 1; i < anArray.length; i++)
			{
				result += ((i % 2 === 1) ? "=" : "&") + anArray[i];
			}
		}
	}
	return result;
};

/**
 * Returns default response handler.
 * @return {Function} Returns default response handler.
 *
 * @see #getResponseHandler
 */
Transporter.prototype.getDefaultHandler = function()
{
	return this.errorHandler();
};

/**
 * Returns response handler according to response status code.
 *
 * @param {Integer} The response status code.
 * @return {Function} Returns response handler according to response status code.
 * Returns custom response handler when it was registered, otherwise
 * returns predefined response handler.
 *
 * @see #getDefaultHandler
 */
Transporter.prototype.getResponseHandler = function(aStatusCode)
{
	var result = this.fResponseHandlers.get(aStatusCode);
	if (!COMMONS.isDefined(result))
	{
		result = this.getDefaultHandler();
	}
	return result;
};

/**
 * Registers default response handler.
 */
Transporter.prototype.registerDefaults = function()
{
	this.setResponseHandeler(400, this.fatalErrorHandler);
	this.setResponseHandeler(500, this.fatalErrorHandler);
	this.setResponseHandeler(0,   this.okHandler);
	this.setResponseHandeler(200, this.okHandler);
};

/**
 * Registers custom response handler.
 *
 * @param {Integer} The response status code.
 * @param {Function} The custom response handler.
 */
Transporter.prototype.setResponseHandeler = function(aStatusCode, aHandler)
{
	this.fResponseHandlers.put(aStatusCode, aHandler);
};

/**
 * Customizes HTTP request headers .
 * @param {XMLHTTPRequest} The XMLHTTPRequest.
 */
Transporter.prototype.customizeHeaders = function(aRequest)
{
	var contentType = (this.fMethod === "POST") ? 'application/x-www-form-urlencoded;charset="utf-8"' :
	                                              'text/xml;charset="utf-8"';
	aRequest.setRequestHeader('Content-type', contentType);
	if ( COMMONS.isGecko )
	{
		aRequest.setRequestHeader('Connection', 'close');
  }
};

/**
 * Forces the transporter to send data to server.
 * <samp>new Transporter().request("controller.jsp", "post", "parameter1", value1, "parameter2", value2);</samp>
 *
 * @param {String} The request URI.
 * @param {String} The request method.
 * @param {String} The request query string.
 */
Transporter.prototype.request = function(aURI, aMethod, aQuery)
{
	this.fURI = aURI;
	this.fTaskCounter = this.fCounter;
	this.fQueryString = aQuery;
	this.fMethod = aMethod;
	Transporter.setTaskAlive(this.fTaskID, true);
	try
	{
		this.doLoadData();
	}
	catch (ex)
	{
		this.fLogger.warning("doLoadData error happened", ex);
	}
};

/**
 * Forces the transporter to send data to server using POST method.
 * <samp>new Transporter().sendData("controller.jsp", "parameter1", value1, "parameter2", value2);</samp>
 *
 * @param {String} The request URI.
 * @param The set of data which should be send to server as ordered pairs of name and value.
 */
Transporter.prototype.sendData = function(aURI)
{
	var query = this.getQueryString(arguments, 1);
	this.request(aURI, "POST", query);
};

/**
 * Forces a transporter to get data from server using GET method.
 * <samp>new Transporter().loadData("controller.jsp", "parameter1", value1, "parameter2", value2);</samp>
 *
 * @param {String} The server URI.
 * @param The set of query parameters which are to be used to obtain response from the server.
 */
Transporter.prototype.loadData = function(aURI)
{
	var query = this.getQueryString(arguments, 1);
	this.request(aURI, "GET", query);
};

/**
 * The inner method of the transporter.
 * Prepares XML HTTP request and sends request to URL.
 */
Transporter.prototype.doLoadData = function()
{
	if (window.XMLHttpRequest)
	{
		this.fReq = new XMLHttpRequest();
	}
	else
	if (window.ActiveXObject)
	{
		if (COMMONS.isDefined(Transporter.ActiveX_TRANSPORT.transport))
		{
			this.fReq = new ActiveXObject(Transporter.ActiveX_TRANSPORT.transport);
		}
		else
		{
			var value;
			for (var i = 0; i < Transporter.ActiveX_TRANSPORT.length; i++)
			{
				value = Transporter.ActiveX_TRANSPORT[i];
				try
				{
					this.fReq = new ActiveXObject(value);
					Transporter.ActiveX_TRANSPORT.transport = value;
					break;
				}
				catch(ex)
				{
				}
			}
		}
	}

	if ( COMMONS.isDefined(this.fReq) )
	{
    this.fProcessed = false;

		var transport = this;
		this.fReq.onreadystatechange = function()
		{
			transport.onReadyState.call(transport);
		};

		try
		{
			this.fReq.open(this.fMethod, this.fURI, this.fAsynch);
			this.customizeHeaders(this.fReq);
			this.fReq.send(this.fQueryString);
			this.fLogger.info("Open request: " + this.fURI + (this.fQueryString ? "?" + this.fQueryString : ""));
			
			if ( !this.fAsynch && COMMONS.isGecko && this.fReq.readyState === 4 )
			{
			  this.onReadyState();
			}
		}
		catch (ex)
		{
			this.fatalErrorHandler();
		}
	}
	else
	{
		this.fLogger.error("Browser not supported XMLHttpRequest");
	}
};

/**
 * The request onreadystatechange call back.
 */
Transporter.prototype.onReadyState = function()
{
	var ready = this.fReq.readyState;
	if (ready === 4)
	{
		if ( !this.fProcessed )
		{
			var handler = this.getResponseHandler(this.fReq.status);
			handler.call(this);
			this.fReq.onreadystatechange = COMMONS.returnTrue;
			this.fProcessed = true;
		}
	}
};

/**
 * Default successful request handler.
 */
Transporter.prototype.okHandler = function()
{
	this.fLogger.info("Request successfully: " + this.fURI);
	if (COMMONS.isFunction(this.onLoad))
	{
		try
		{
			this.onLoad.call(this);
		}
		catch(ex)
		{
			this.fLogger.error("Callback error: " + this.fURI, ex, this.onLoad);
		}
	}
	Transporter.setTaskAlive(this.fTaskID, false);
};

/**
 * Fatal error handler. It called on very severe error
 * that will require the transporter to abort
 * XML HTTP request.
 */
Transporter.prototype.fatalErrorHandler = function()
{
	if (this.fReqTaskID !== null)
	{
		window.clearTimeout(this.fReqTaskID);
		this.fReqTaskID = null;
	}
	Transporter.setTaskAlive(this.fTaskID, false);
	if (COMMONS.isDefined(this.fReq))
	{
		this.fLogger.error(this.fReq.status + ", request " + this.fURI + " error. Headers: " +
		                   this.fReq.getAllResponseHeaders());

		this.fReq.onreadystatechange = COMMONS.returnTrue;
		this.fReq.abort();
	}
};

/**
 * Error handler. It called on request error
 * and allowes the transporter to try the request again,
 * after short waiting.
 */
Transporter.prototype.errorHandler = function()
{
	if (this.fReqTaskID !== null)
	{
		window.clearTimeout(this.fReqTaskID);
		this.fReqTaskID = null;
	}
	if (this.fTaskCounter <= 0)
	{
		Transporter.setTaskAlive(this.fTaskID, false);
		this.fLogger.error(this.fReq.status + ", request  " + this.fURI + " error. Headers: " +
		                   this.fReq.getAllResponseHeaders());
	}
	else
	{
		var transporter = this;
		this.fTaskCounter = this.fTaskCounter - 1;
		this.fReqTaskID = window.setTimeout(function()
		{
			transporter.doLoadData();
		}, this.fTimeout);
		this.fLogger.info(this.fReq.status + ", trying to request " + this.fURI + " again....");
	}
};

/**
 * Returns XML HTTP request responsed text.
 * @return {String} Returns XML HTTP request responsed text.
 */
Transporter.prototype.getResponsedText = function()
{
	var result = null;
	if (COMMONS.isDefined(this.fReq))
	{
		result = this.fReq.responseText;
	}
	return result;
};

/**
 * Returns XML HTTP request responsed XML.
 * @return {String} Returns XML HTTP request responsed XML.
 */
Transporter.prototype.getResponsedXML = function()
{
	var result = null;
	if (COMMONS.isDefined(this.fReq))
	{
		try
		{
			result = this.fReq.responseXML;
		}
		catch(ex)
		{
			this.fLogger.error("Unable to parse responsed XML", ex);
		}
	}
	return result;
};

/**
 * JavaScript dependency injector.
 *
 * @param {Array} The object dependecy as array of dependency keys which should be resolved.
 * @param {Function} The call back function invocated when all object dependency loaded.
 *
 * @see #extend
 */
JSINER.inject = function(aDependency, aCallBack)
{
	var getUri = function(aLoader, aDependency)
	{
		var result = null;
		for (var i = aLoader.fIndex; i < aDependency.length; i++)
		{
			var link = aDependency[aLoader.fIndex];
			if (!JSINER.isScriptLoaded(link))
			{
				result = JSINER.getScriptURI(link);
				if (result !== null)
				{
					aLoader.fIndex = i;
					break;
				}
			}
		}
		return result;
	};

	if ( COMMONS.isDefined(aDependency) )
	{
		if ( !COMMONS.isArray(aDependency) )
		{
			aDependency = [aDependency];
		}

		var loader = new Transporter(function()
		{
			var code = this.getResponsedText();
			if (window.execScript)
			{
				window.execScript(code, 'javascript');
			}
			else
			if (COMMONS.isSafari)
			{
				var heads = document.getElementsByTagName('head');
			  var head = heads.length > 0 ? heads[0] : document.body;

				var script = document.createElement('script');
				script.type = 'text/javascript';
				script.innerHTML = code;
				head.appendChild(script);
			}
			else
			{
				window.eval(code);
			}

			JSINER.fScripts.add(aDependency[this.fIndex]);
			this.fIndex++;

			var uri = getUri(this, aDependency);
			if (uri !== null )
			{
				this.loadData(uri);
			}
			else
			if ( COMMONS.isFunction(aCallBack) )
			{
				aCallBack();
			}
		});
		loader.fAsynch = false;
		loader.fIndex = 0;

		var uri = getUri(loader, aDependency);
		if ( uri !== null)
		{
			loader.loadData(uri);
		}
		else
		if ( COMMONS.isFunction(aCallBack) )
		{
			aCallBack();
		}
	}
};


var JSONER =
{
	version: 1.024
};

/**
  * JSONER's constuctor.
  *
  * JSONER is a collection of solutions for most commonly
  * used operations performed with JSON.
  * JSONER allows developers to easily and quickly build rich JSON based web applications
  *
  * JSONER is based on event - event handler paradigm (like SAX).
  * An event-based API reports parsing events (such as the start and end of JSON node)
  * directly to the application through callbacks.
  * In both these cases, an event-based API provides a simpler, lower-level access to JSON data structure.
  *
  * @constructor
  */
function Jsoner()
{
	/**
	  * The map used to precache JSON path - lookup functions to improve performance.
	  * The ones can be used to register custom value providers too.
	  * @type Map
	  * @see Jsoner#registerDataProvider
	  */
  this.fDataProviderCache = new HashMap();
	this.fLogger = new Logger("Jsoner");

	/**
	 * Indicates that the walking node is array.
	 * Protected method.
	 * @return {Boolean} Returns true if it true, otherwise - false.
	 *
	 * @param {Array} The JSON path as array.
	 * @param The JSON node value.
	 * @param The top level JSON object.
	 *
	 * @see #jsonTreeWalker
	 */
	this.isWalkArray = function(aName, aValue, aJson)
	{
		return COMMONS.isArray(aValue);
	};

	/**
	 * Indicates that the walking object represents JSON node.
	 * Protected method.
	 * @return {Boolean} Returns true if it true, otherwise - false.
	 *
	 * @param {Array} The JSON path as array.
	 * @param The JSON node value.
	 * @param The JSON object.
	 *
	 * @see #jsonTreeWalker
	 */
	this.isWalkNode = function(aName, aValue, aJson)
	{
		return COMMONS.isObject(aValue) && !COMMONS.isDate(aValue) && !COMMONS.isRegExp(aValue);
	};
}

/**
  * Predefined JSON event type.
  * It confirms that a branch node starting.
  * @type Number
  * @final
  */
Jsoner.JSON_NODE_START = 1;

/**
  * Predefined JSON event type.
  * It confirms that a branch node closing.
  * @type Number
  * @final
  */
Jsoner.JSON_NODE_END = 2;

/**
  * Predefined JSON event type.
  * It confirms that a leaf node starting.
  * @type Number
  * @final
  */
Jsoner.JSON_NODE_LEAF = 3;

/**
  * Predefined JSON event type.
  * It confirms that a node that represented as attribute starting.
  * @type Number
  * @final
  */
Jsoner.JSON_ATTRIBUTE = 4;

/**
  * Predefined JSON event type.
  * It confirms that a branch node cross linked.
  * @type Number
  * @final
  */
Jsoner.JSON_NODE_CROSS_LINKED = 5;

/**
  * Predefined property name.
  * The property used to break cross linked collisions.
  * @type String
  * @private
  */
Jsoner.MAGIC_HASH_CODE = "$lnk";

/**
  * Predefined cross linked node value prefix.
  * @type String
  * @final
  */
Jsoner.CROSS_LINK_PREFIX = "#link:";

/**
  * Checks if the value matches pattern.
  * @return {Boolean} Returns true if a value is matched pattern.
  *
  * @param The pattern as String or RegExp.
  * @param The value.
  *
  * <ul>
  *  <span>Available types of pattern: </span>
  *  <li> A string with wildcard asterisk (*), that substituted for any characters in a path.
  *  <li> A string without wildcard that matched to equals.
  *  <li> A RegExp pattern.
  * </ul>
  *
  * <ul>
  *  <span>Limitation: only one asterisk supported.</span>
  *  <li> The path started with asterisk (*) represents end part of the path.
  *  <li> The path end of asterisk (*) represents first part of the path.
  *  <li> The path contains asterisk (*) in the middle of text represents first and end paths of the path.
  * </ul>
  */
Jsoner.prototype.isMatch = function(aPattern, aValue)
{
	var result = false;
	if (COMMONS.isDefined(aPattern))
	{
		var string = String(aValue);
		if (COMMONS.isRegExp(aPattern))
		{
			result = aPattern.test(string);
		}
		else
		if (COMMONS.isString(aPattern))
		{
			var index = aPattern.indexOf('*');
			if (index === -1)
			{
				result = (aValue === aPattern);
			}
			else
			if (index === 0)
			{
				if (aPattern.length > 1)
				{
					var tmp = aPattern.substr(1);
					result = string.lastIndexOf(tmp) === (string.length - tmp.length);
				}
			}
			else
			{
				var tokens = aPattern.split('*');
				result = string.indexOf(tokens[0]) === 0;
				if (result && tokens.length > 1)
				{
					var lastToken = tokens[tokens.length - 1];
					result = string.lastIndexOf(lastToken) === (string.length - lastToken.length);
				}
			}
		}
	}
	return result;
};

/**
  * Factory used to create a converter based on argument type.
  * @return {Function} Returns dummy converter by undefined argument,
  * himself argument by funtion argument or proxy by Map argument.
  *
  * @param The converter template.
  */

Jsoner.prototype.converterFactory = function(aConverter)
{
	var result = COMMONS.proxy;
	if ( COMMONS.isFunction(aConverter) )
	{
    result = aConverter;
	}
	else
	if ( COMMONS.isObject(aConverter) )
	{
		result = function(aValue)
		{
			for(var name in aConverter )
			{
				if ( aConverter.hasOwnProperty(name) && this.isMatch(name, aValue) )
				{
					return aConverter[name];
				}
			}
			return aValue;
		};
	}
	return result;
};

/**
  * Populates the value to JSON object using the path based way to compute a place in JSON object.
  * @see #setValue
  *
  * @param {JSON} The JSON object.
  * @param {String} The path defined a way to compute a place in JSON model
  * and includes different type of nodes or attribute.
  * @param The value.
  * @param {Boolean} The flag defines behavior of populator if node in the path is missed.
  * If it is true, missing nodes with corresponding by path type (Object or Array)
  * will be created otherwise the value will be not populated.
  *
  * @return {JSON} The modified JSON object, useful to make chank of changes.
  */
Jsoner.prototype.populate = function(aJson, aPath, aValue, aCreateMissing)
{
  function parseSegment(aSegment)
  {
	  var result = aSegment;
	  if ( aSegment.charAt(aSegment.length - 1) === ']' )
	  {
		  var index = aSegment.indexOf("[");
		  result = {path:aSegment.substring(0, index),
			          index:aSegment.substring(index + 1, aSegment.length-1)};
		}
	  return result;
  }

	var path = aPath.split('.');
	var obj = aJson;
	var tmpObj;
	var segment;
	for (var i = 0; (i < path.length - 1) && (obj !== null); i++)
	{
		segment = parseSegment(path[i]);
		if ( COMMONS.isString(segment) )
		{
			tmpObj = obj[segment];
			if ( aCreateMissing )
			{
				if ( !COMMONS.isDefined(tmpObj) )
				{
					tmpObj = {};
					obj[segment] = tmpObj;
				}
				else
				if ( COMMONS.isArray(tmpObj) && !COMMONS.isDefined(tmpObj[0]) )
				{
					tmpObj[0] = {};
				}
			}
			obj = COMMONS.isArray(tmpObj) ? tmpObj[0] : tmpObj;
		}
		else
		{
			tmpObj = obj[segment.path];
			if ( !COMMONS.isDefined(tmpObj) && aCreateMissing )
			{
				tmpObj = [];
				obj[segment.path] = tmpObj;
			}
			else
			if ( !COMMONS.isArray(tmpObj) )
			{
				tmpObj = [tmpObj];
				obj[segment.path] = tmpObj;
			}
			obj = tmpObj;

			if ( COMMONS.isDefined(obj) )
			{
				tmpObj = obj[segment.index];
				if ( !COMMONS.isDefined(tmpObj) && aCreateMissing )
				{
					tmpObj = {};
					obj[segment.index] = tmpObj;
				}
				obj = tmpObj;
			}
		}
	}

	if ( COMMONS.isDefined(obj) )
	{
		segment = parseSegment(path[path.length - 1]);
		if ( COMMONS.isString(segment) )
		{
			obj[segment] = aValue;
		}
		else
		{
			tmpObj = obj[segment.path];
	    if ( !COMMONS.isDefined(tmpObj) )
			{
				tmpObj = [];
				obj[segment.path] = tmpObj;
			}
			else
			if ( !COMMONS.isArray(tmpObj) )
			{
				tmpObj = [tmpObj];
				obj[segment.path] = tmpObj;
			}
			tmpObj[segment.index] = aValue;
		}
	}
	return aJson;
};

/**
  * Registers data provider method by path in JSON.
  * @param {String} The path defines a way to compute a value in JSON model.
  * @param {Function} The data providing method.
  *
  * @see #getValue
  */
Jsoner.prototype.registerDataProvider = function(aPath, aFunction)
{
	this.fDataProviderCache.put(aPath, aFunction);
};

/**
  * Gets value from JSON model safe.
  * @param {JSON} The JSON object.
  * @param {String} The path defines a way to compute a value in JSON model.
  *
  * @return The value by path in JSON if data model by path is full defined
  * otherwise it returns undefined.
  */
Jsoner.prototype.getValue = function(aJson, aPath)
{
	var result = undefined;
	if ( COMMONS.isObject(aJson) )
	{
		try
		{
			result = aJson[aPath];
			if ( COMMONS.isUndefined(result) )
			{
				var fnc = this.fDataProviderCache.get(aPath);
				if ( !COMMONS.isFunction(fnc) )
				{
					var fncBody = "return aData";
					if ( aPath.length > 0)
					{
					  if ( aPath.charAt(0) === "[")
					  {
						  fncBody += aPath;
					  }
						else
					  {
						  fncBody += "." + aPath;
					  }
					}
					fnc = new Function("aData", fncBody );
					this.registerDataProvider(aPath, fnc);
				}
				result = fnc.call(this, aJson);
			}
		}
		catch(ex)
		{
		}
	}
	return result;
};

/**
  * Safe sets value to JSON model.
  *
  * @param {JSON} The JSON object.
  * @param {String} The path defines a way to compute a place in JSON model.
  * If nodes in the path are missed they will be created with corresponding to path type (Object or Array).
  * @param The Value.
  * @param {Boolean} The flag defines behavior if node in the path is missed.
  * If it is true, missing nodes with corresponding by path type (Object or Array)
  * will be created otherwise the value will be not assigned.
  * It's true by defaults.
  *
  * @return {JSON} The modified JSON object, useful to make chank of changes.
  * @see #populate
  */
Jsoner.prototype.setValue = function(aJson, aPath, aValue, aCreateMissing)
{
	var result = aJson;
	if ( COMMONS.isObject(aJson) )
	{
		var createMissing = (COMMONS.isUndefined(aCreateMissing) || aCreateMissing);
		this.populate(aJson, aPath, aValue, createMissing);
	}	
	return result;
};

/**
  * Indicates that the JSON property should be ignored.
	* @return {Boolean} If so it returns true, otherwise it returns false.
	*
  * @param {String} The property name.
  * @param The property value.
  * @param The parent object.
  *
  * The method can be overloaded to transform JSON event output.
  * @see #jsonToXML.
  */
Jsoner.prototype.isMute = function(aName, aValue, aParent)
{
	var result = aName === Jsoner.MAGIC_HASH_CODE || !aParent.hasOwnProperty(aName) || COMMONS.isFunction(aValue);
	return result;
};

/**
  * Indicates that the JSON property should be represented as an attribute.
	* @return {Boolean} If so it returns true, otherwise it returns false.
  * @param {String} The property name.
  * @param The property value.
  *
  * The method can be overloaded to transform JSON event output.
  * @see #jsonToXML.
  */
Jsoner.prototype.isAttribute = function(aName, aValue)
{
	var result = true;
	if ( aValue === null || COMMONS.isObject(aValue) )
	{
		result = COMMONS.isDate(aValue) || COMMONS.isRegExp(aValue) || aValue === null;
	}
	return result;
};

/**
  * Indicates that the JSON attribute should be represented as a text node.
  * @return {Boolean} If so it returns true, otherwise it returns false.
  * @param {String} The attribute name.
  *
  * @see #isAttribute
  */
Jsoner.prototype.isText = function(anAttributeName)
{
	return (anAttributeName === "text");
};

/**
  * Indicates that the JSON attribute should be represented as CDATA.
  * @return {Boolean} It returns true if so, otherwise it returns false.
  * @param {String} The attribute name.
  *
  * @see #isAttribute
  */
Jsoner.prototype.isCDATA = function(anAttributeName)
{
	return (anAttributeName === "PCDATA");
};

/**
  * Collects the JSON attributes to array as pair name-value
  * <samp>{name:name, value:value}</samp>.
  * @return {Array} An array of attributes.
  *
  * @param The JSON path as array or String.
  * @param The JSON node value.
  * @param The top level JSON object.
  * 
  * @see #isAttribute.
  */
Jsoner.prototype.collectAttributes = function(aPath, aValue, aJson)
{
	var result = [];
	var value;
	
	if ( COMMONS.isObject(aValue) )
	{
		for (var name in aValue)
		{
			try
			{
				value = aValue[name];
				if ( !this.isMute(name, value, aValue) && this.isAttribute(name, value) )
				{
					result.push( {name:name, value:value} );
				}
			}
			catch(ex)
			{
				this.fLogger.warning( "collectAttributes, unable to collect attribute:" + name, ex);
			}
		}
	}	
	return result;
};

/**
  * Collects the JSON children to array as pair name-value
  * <samp>{name:name, value:value}</samp>.
  * @return {Array} An array of node children.
  *
  * @param The JSON path as array or String.
  * @param The JSON node value.
  * @param The top level JSON object.
  *
  * @see #collectAttributes.
  */
Jsoner.prototype.collectChildren = function(aPath, aValue, aJson)
{
	var result = [];
	var value;
	for (var name in aValue)
	{
		try
		{
			value = aValue[name];
			if ( !this.isMute(name, value, aValue) && !this.isAttribute(name, value) )
			{
				result.push( {name:name, value:value} );
			}
		}
		catch(ex)
		{
			this.fLogger.warning( "collectChildren, unable to collect child:" + name, ex);
		}
	}
	return result;
};

/**
 * Indicates that cross link collisions resolver is turn on.
 *
 * @return {Boolean} Returns true if so, otherwise - false.
 * @param {JSON} The JSON object.
 */
Jsoner.prototype.isResolveCrossLinks = function(anObject)
{
	return true;
};

/**
  * Adds special property which used to break cross linked collisions.
  * @private
  *
  * @param {JSON} The JSON object.
  * @param The property value.
  */
Jsoner.prototype.addHashCode = function(anObject, aValue)
{
	if ( COMMONS.isObject(anObject) )
	{
    anObject[Jsoner.MAGIC_HASH_CODE] = aValue;
	}
};

/**
  * Returns value of property which uses to break cross linked collisions.
  * @private
  *
  * @param {JSON} The JSON object.
  * @return Returns property value.
  *
  */
Jsoner.prototype.getHashCode = function(anObject)
{
	var result = undefined;
	if ( COMMONS.isObject(anObject) )
	{
		result = anObject[Jsoner.MAGIC_HASH_CODE];
  }
	return result;
};

/**
  * Removes special property which uses to break cross linked collisions.
  * @private
  *
  * @param {JSON} The JSON object.
  */
Jsoner.prototype.removeHashCode = function(anObject)
{
	if ( COMMONS.isObject(anObject) && anObject[Jsoner.MAGIC_HASH_CODE] !== undefined )
	{
		anObject[Jsoner.MAGIC_HASH_CODE] = undefined;
		delete anObject[Jsoner.MAGIC_HASH_CODE];
	}
};

/**
  * Traverses the JSON object.
  * <ul>
  * <span> Types of events: </span>
  *  <li> JSON_NODE_START - a branch node starting.
  *  <li> JSON_NODE_END   - a branch node closing.
  *  <li> JSON_NODE_LEAF  - a leaf node starting.
  *  <li> JSON_ATTRIBUTE  - a node, that represented as an attribute starting.
  *  <li> JSON_CROSS_LINKED - a cross linked node starting.
  * </ul>
  * </p>
  *
  * @param {JSON} The JSON object.
  * @param {Function} The callBack function, called to process when the branch of JSON object starting
  * or closing happens.
  * <ul>
  * <span>List of arguments passed to the callBack function:</span>
  *  <li> The path to traversed node as array of string.
  *  <li> The JSON node value.
  *  <li> The collection of attributes as pair name-value <samp>{"name":name, "value":value}</samp>.
  *  <li> The event type.
  *  <li> The JSON node level.
  *  <li> The JSON node index within a parent node.</li>
  * <span> The callBack function should return true to continue tree traversing,
  * otherwise traversing is stopped. </span>
  * </ul>
  */
Jsoner.prototype.jsonTreeWalker = function(aJson, aCallBack)
{
	var level = -1;
	var path = [];

	var result = true;
	var map = new HashMap();

	function walkNode(aName, aValue, aLevel, aIndex)
	{
		var attributes, index, value;
		if (result)
		{
			if (this.isWalkArray(path, aValue, aJson))
			{
				for (var i = 0; i < aValue.length && result; i++)
				{
					walkNode.call(this, aName, aValue[i], aLevel, i);
				}
			}
			else
			{
				var currentPath = COMMONS.isDefined(aIndex) ? aName + "[" + aIndex + "]" : aName;
				if (aLevel > level)
				{
					path.push(currentPath);
					level = aLevel;
				}
				else
				{
					path[aLevel] = currentPath;
				}
				if ( this.isWalkNode(path, aValue, aJson) )
				{
					try
					{
						attributes = this.collectAttributes(path, aValue, aJson);
						index = this.getHashCode(aValue);
						if (COMMONS.isUndefined(index))
						{
							if ( this.isResolveCrossLinks(aValue) )
							{
								index = map.getSize();
								this.addHashCode(aValue, index);
								map.put(index, aName);
							}
							try
							{
								var children = this.collectChildren(path, aValue, aJson);
								if ( children.length > 0  )
								{
									try
									{
										result = aCallBack.call(this, path, aValue, attributes, Jsoner.JSON_NODE_START, aLevel, aIndex);
									}
									catch(ex)
									{
										this.fLogger.error("jsonTreeWalker, [" + path + "] call back error", ex);
									}
									if (result)
									{
										for (var i = 0; i < children.length && result; i++)
										{
											walkNode.call(this, children[i].name, children[i].value, aLevel + 1, null);
										}
										path.pop();
										level--;
										result = aCallBack.call(this, path, aValue, null, Jsoner.JSON_NODE_END, aLevel, aIndex);
									}
								}
								else
								{
									try
									{
										result = aCallBack.call(this, path, aValue, attributes, Jsoner.JSON_NODE_LEAF, aLevel, aIndex);
									}
									catch(ex)
									{
										this.fLogger.error("jsonTreeWalker, [" + path + "] call back error", ex);
									}
								}
							}
							finally
							{
								this.removeHashCode(aValue);
							}
						}
						else
						{
							value = map.get(index);
							try
							{
								result = aCallBack.call(this, path, value, attributes, Jsoner.JSON_NODE_CROSS_LINKED, aLevel, aIndex);
							}
							catch(ex)
							{
								this.fLogger.error("jsonTreeWalker, [" + path + "] call back error", ex);
							}
						}
					}
					catch(exception)
					{
						this.fLogger.error("jsonTreeWalker, traverse node " + aName + " failed", exception);
					}
				}
				else
				{
					result = aCallBack.call(this, path, aValue, null, Jsoner.JSON_ATTRIBUTE, aLevel, aIndex);
				}
			}
		}
	}

	if (COMMONS.isFunction(aCallBack))
	{
		if ( this.isWalkArray([], aJson, aJson))
		{
			walkNode.call(this, "", aJson, 0);
		}
		else
		{
			var value;
			for (var name in aJson)
			{
				try
				{
					value = aJson[name];
					if ( !this.isMute(name, value, aJson) )
					{
						walkNode.call(this, name, value, 0);
					}
				}
				catch(ex)
				{
					this.fLogger.info("jsonTreeWalker, unable to walk object property: " + name, ex );
				}
			}
		}
		map.clear();
	}
	else
	{
		this.fLogger.error("jsonTreeWalker, callback function undefined");
	}
};

/**
 * Returns last property name by JSON path that represented as an array.
 * @param {JSON} The JSON path as array.
 *
 * @return {String} Returns last token by JSON path.
 */
Jsoner.prototype.getLastProperty = function(aPath)
{
	var result = undefined;
	if ( COMMONS.isArray(aPath) )
	{
		result = aPath[aPath.length - 1];
		if ( result.charAt(result.length - 1) ===']' )
		{
			var index = result.indexOf("[");
			if (index > 0)
			{
				result = result.substring(0, index);
			}
		}	
	}
	return result;
};

/**
 * Returns a XML representation of the JSON object based on tree traversing.
 * @return {String} Returns a XML representation of the JSON object based on tree traversing
 * @param {JSON} The JSON object.
 * @param {Boolean} The pretty print flag.
 *
 * @param The node name converter as function or Map.
 *  <ul>
 *  <span>List of arguments passed to the converter in case of a function:</span>
 *   <li> The JSON node name.
 *   <li> The JSON path as array.
 *   <li> The event type.</li>
 *  <span> Converter returns presentation of XML node name.</span>
 *  </ul>
 *
 * @param The attribute name converter as function or Map.
 *  <ul>
 *  <span>List of arguments passed to the converter in case of converter is a function:</span>
 *   <li> The attribute name.
 *   <li> The attribute value.
 *   <li> The JSON path as array.</li>
 *  <span>Converter returns presentation of XML node attribute name.</span>
 *  </ul>
 *
 * @param The attribute value converter as function or Map.
 *  <ul>
 *  <span>List of arguments passed to the converter in case of function:</span>
 *   <li> The attribute value.
 *   <li> The attribute name.
 *   <li> The JSON path as array.
 *   <li> The JSON event type.</li>
 *  <span>Converter returns presentation of XML node attribute value.</span>
 *  </ul>
 *
 */
Jsoner.prototype.jsonToXML = function(aJson, aPrettyPrint, aNodeConverter,
                                      anAttributeConverter, aValueConverter)
{
	var getPrettyPrintTab = function(aLevel)
	{
		var result = "";
		for (var i = 0; i < aLevel; i++)
		{
			result += " ";
		}
		return result;
	};

	var atttibuteValueConverter = function(aValue, aName, aPath, aType)
	{
		var result = aValue;
		if (aType === Jsoner.JSON_NODE_CROSS_LINKED )
		{
			result = Jsoner.CROSS_LINK_PREFIX + result;
		}
		return result;
	};

	var result = "";
	var nodeConverter = this.converterFactory(aNodeConverter);
	var attributeConverter = this.converterFactory(anAttributeConverter);
	var valueConverter = this.converterFactory(aValueConverter ? aValueConverter : atttibuteValueConverter);

	this.jsonTreeWalker(aJson, function(aPath, aValue, anAttributes, aType)
	{
		var value;
		var name;
		var attribute;

    var nodeName = nodeConverter.call(this, this.getLastProperty(aPath), aPath, aType);
		if ( COMMONS.isDefined(nodeName) )
		{
			if ( aPrettyPrint )
			{
				result += getPrettyPrintTab(aPath.length -1);
			}

			if ( aType === Jsoner.JSON_NODE_START || aType === Jsoner.JSON_NODE_LEAF)
			{
				var CDATA = "";
				var text = "";
				result += "<" + nodeName;
				if ( COMMONS.isArray(anAttributes) )
				{
					for(var i = 0; i < anAttributes.length; i++)
					{
						attribute = anAttributes[i];
						name = attribute.name;

						value = valueConverter.call(this, attribute.value, name, aPath, aType);
						if ( !COMMONS.isUndefined(value) )
						{
							name = attributeConverter.call(this, name, value, aPath);
							if ( COMMONS.isDefined(name) )
							{
								if ( this.isText(name) )
								{
									text += value;
								}
								else
								if (this.isCDATA(name) )
								{
									CDATA += value;
								}
								else
								{
									result += " " + name + "=\"" + value + "\"";
								}
							}
						}
					}
				}

				if ( CDATA.length > 0 || text.length > 0 )
				{
					result += ">";
					if ( aPrettyPrint )
					{
						result += "\n"+ getPrettyPrintTab(aPath.length);
					}
					result += ( CDATA.length > 0 ) ? "<![CDATA[" + CDATA + text + "]]>" : text;
					if (aType === Jsoner.JSON_NODE_LEAF)
					{
						if ( aPrettyPrint )
						{
							result += "\n"+ getPrettyPrintTab(aPath.length -1);
						}
						result += "</" + nodeName + ">";
					}
				}
				else
				{
					result += (aType === Jsoner.JSON_NODE_LEAF) ? "/>" : ">";
				}
			}
			else
			if ( aType === Jsoner.JSON_NODE_END)
			{
				result += "</" + nodeName + ">";
			}
			else
			if ( aType === Jsoner.JSON_ATTRIBUTE || aType === Jsoner.JSON_NODE_CROSS_LINKED )
			{
				value = valueConverter.call(this, aValue, nodeName, aPath, aType);
				if ( COMMONS.isDefined(value) )
				{
					result += "<" + nodeName + ">" + value + "</" + nodeName + ">";
				}
			}

			if (aPrettyPrint)
			{
				result += "\n";
			}
		}
		return true;
	});
	
  return result;
};

/**
  * Converts traverse tree events to path-value events.
  *
  * @param {JSON} The JSON object.
  * @param {Function} The callBack function called to process when the branch of JSON object
  * starting is encountered.
  * <ul>
  * <span> List of arguments passed to the callBack function: </span>
  *  <li> The path in JSON model.
  *  <li> The value of JSON node.
  *  <li> The JSON event type.
  * </ul>
  */
Jsoner.prototype.jsonPathEvaluator = function(aJson, aCallBack)
{
	var result = true;

	this.jsonTreeWalker(aJson, function(aPath, aValue, anAttributes, aType)
	{
		var attribute;
		var value;

		if ( aType === Jsoner.JSON_NODE_START || aType === Jsoner.JSON_NODE_LEAF ||
		     aType === Jsoner.JSON_ATTRIBUTE || aType === Jsoner.JSON_NODE_CROSS_LINKED) 
		{
			var xPath = aPath.join('.');
			if ( aType === Jsoner.JSON_NODE_CROSS_LINKED )
			{
				var last = xPath.lastIndexOf(aValue);
				value = Jsoner.CROSS_LINK_PREFIX + (last > 0 ? xPath.substring(0, last + aValue.length) : aValue);
				result = aCallBack.call(this, xPath, value, aType);
			}
			else
			if ( COMMONS.isArray(anAttributes) )
			{
				for(var i = 0; i < anAttributes.length; i++)
				{
					attribute = anAttributes[i];
					result = aCallBack.call(this, xPath + "." + attribute.name, attribute.value, aType);
					if ( !result )
					{
						break;
					}
				}
			}
			else
			{
				result = aCallBack.call(this, xPath, aValue, aType);
			}
		}
		return result;
	});
};

/**
  * Returns path-value representation of JSON object.
  * @return {String} Returns path-value representation of JSON.
  *
  * @param {JSON}The JSON object.
  */
Jsoner.prototype.jsonToPathValue = function(aJson)
{
	 var result = "";
	 this.jsonPathEvaluator(aJson, function(aPath, aValue, aType)
	 {
			result += aPath + " = " + aValue + "\n";
		  return true;
	 });
	return result;
};

/**
  * Creates new instance of the object.
  *
  * @return Returns new instance of the object.
  * @param The object.
  *
  * @see #clone
  */
Jsoner.prototype.createNewInstance = function(aJson)
{
  var result = aJson;
	if ( COMMONS.isObject(aJson) )
	{
   	var cons = JSINER.getConstructor(aJson);
  	result = new cons();
	}
	return result;
};

/**
  * Creates deep copy of the JSON object.
  * Recursive clones all JSON properties except attributes.
  * Skips ignored properties.
  *
  * @return {JSON} Returns a deep copy of the JSON object.
  * @param {JSON} The JSON object.
  *
  * @see #isAttribute
  * @see #isMute
  */
Jsoner.prototype.clone = function(aJson)
{
	var map = new HashMap();

	var doClone = function(json)
	{
		var result;
	  var value;
		var index = this.getHashCode(json);
		if ( COMMONS.isUndefined(index) )
		{
			result = this.createNewInstance(json);
      if ( this.isResolveCrossLinks(json) )
      {
				index = map.getSize();
				this.addHashCode(json, index);
				map.put(index, result);
	    }
      try
      {
				for (var name in json)
				{
					value = json[name];
					if ( !this.isMute(name, value, json) )
					{
						if ( !this.isAttribute(name, value) )
						{
							index = this.getHashCode(value);
							if ( COMMONS.isDefined(index) )
							{
								value = map.get(index);
							}
							else
							{
								value = doClone.call(this, value);
							}
						}
						result[name] = value;
					}
				}
	    }
			finally
      {
				this.removeHashCode(json);
	    }
		}
		else
		{
			result = map.get(index);
		}
		return result;
	};

	var result = doClone.call(this, aJson, map);
	map.clear();
	return result;
};

/**
  * Creates and returns a merged JSON object
  *
  * @param {JSON} The primary JSON object.
  * @param {JSON} The secondary JSON object.
  * @param {Boolean} The flag defined the missing nodes in result JSON should be created or not.
  * It's true by defaults.
  *
  * @return {JSON} The result of merge.
  */
Jsoner.prototype.merge = function(aTemplate, aJson, aCreateMissing)
{
	var result = this.clone(aTemplate);
	var createMissing = (COMMONS.isUndefined(aCreateMissing) || aCreateMissing);
	var map = new HashMap();

	if ( COMMONS.isObject(aJson) && COMMONS.isObject(aTemplate) )
	{
		this.jsonPathEvaluator(aJson, function(aPath, aValue, aType)
		{
			if ( aType !== Jsoner.JSON_NODE_CROSS_LINKED )
			{
				var populate = COMMONS.isUndefined( this.getValue(result, aPath) );
				if ( !populate )
				{
					var index = aPath.lastIndexOf('.');
					if ( index > 0 )
					{
						var name = aPath.substring(index + 1);
						populate = this.isAttribute(name, aValue);
					}
				}
				if ( populate )
				{
					if ( COMMONS.isString(aValue) && aValue.indexOf(Jsoner.CROSS_LINK_PREFIX) === 0 )
					{
						map.put( aPath, aValue.substring(Jsoner.CROSS_LINK_PREFIX.length));
					}
					else
					{
						this.populate(result, aPath, aValue, createMissing);
					}
				}
			}
			else
			{
				map.put( aPath, aValue.substring(Jsoner.CROSS_LINK_PREFIX.length));
			}
		  return true;
		});
		
		if ( !map.isEmpty() )
		{
			var value;
			for( var name in map.fObject )
			{
				if ( map.fObject.hasOwnProperty(name) )
				{
					value = this.getValue(result, map.get(name) );
				  this.populate(result, name, value, createMissing);
				}
			}
		}
	}

	return result;
};

/**
  * Indicates that two JSON objects are equal.
  *
  * @return {Boolean} Returns true if the objects are equal, false - otherwise.
  * @param {JSON} The first JSON object.
  * @param {JSON} The second JSON object.
  */
Jsoner.prototype.isEquals = function(aJson1, aJson2)
{
	var isObjectEquals = function(aJson1, aJson2)
	{
		var result = true;
		var crossLinks = new HashMap();
		var pathSet = new KeySet();

		this.jsonPathEvaluator(aJson1, function(aPath, aValue, aType)
		{
			if ( aType !== Jsoner.JSON_NODE_CROSS_LINKED )
			{
				if ( !this.isEquals(aValue, this.getValue(aJson2, aPath)) )
				{
					this.fLogger.info("isEquals, difference found:" + aPath);
					result = false;
				}
				else
				{
					pathSet.add(aPath);
				}
			}
			else
			{
				crossLinks.put(aPath, aValue);
			}
			return result;
		});

		if (result)
		{
			this.jsonPathEvaluator(aJson2, function(aPath, aValue, aType)
			{
				if (!pathSet.isContains(aPath))
				{
					if (aType !== Jsoner.JSON_NODE_CROSS_LINKED)
					{
						if ( !this.isEquals(aValue, this.getValue(aJson1, aPath)) )
						{
							this.fLogger.info("isEquals, difference found:" + aPath);
							result = false;
						}
					}
					else
					if ( !this.isEquals(aValue, crossLinks.get(aPath)) )
					{
						this.fLogger.info("isEquals, cross link not equal:" + aPath);
						result = false;
					}
					else
					{
						crossLinks.remove(aPath);
					}
				}
				return result;
			});
		}
		return result && crossLinks.isEmpty();
	};

	var result = JSINER.getType(aJson1) === JSINER.getType(aJson2);
	if ( result )
	{
		if ( COMMONS.isObject(aJson1) )
		{
			if ( COMMONS.isArray(aJson1) )
			{
				result = (aJson1.length === aJson2.length);
			}
			if ( result )
			{
				result = isObjectEquals.call(this, aJson1, aJson2);
			}
		}
		else
		{
			result = (aJson1 === aJson2);
		}
	}
	return result;
};

/** 
 * Creates an object that represents a difference between
 * two JSON objects.
 * The method getDifference is contrary to getMerge method.
 * The  given JSON object can be restored by getMerge(aJson, difference) operation.
 *
 * @return {JSON} Returns object that represents a difference between two JSON objects.
 * @param {JSON} The first JSON object.
 * @param {JSON} The second JSON object.
 */
Jsoner.prototype.getDifference = function(aTemplate, aJson)
{
	var parsePath = function(aPath)
	{
		var result = aPath;
		var index = aPath.lastIndexOf("]");
		if ( index > 0 && index < aPath.length - 1)
		{
			var bIndex = aPath.lastIndexOf("[");
			result = { path:aPath.substring(0, bIndex),
				         index:COMMONS.toInteger(aPath.substring(bIndex + 1, index)),
				         property:aPath.substring(index + 2) };
		}
		return result;
	};

	var doDifference = function(aTemplate, aJson, aResult)
	{
		var crossLinks = new HashMap();
		var pathSet = new KeySet();

		this.jsonPathEvaluator(aTemplate, function(aPath, aValue, aType)
		{
			if ( aType !== Jsoner.JSON_NODE_CROSS_LINKED )
			{
				pathSet.add(aPath);
				if ( !this.isEquals(aValue,this.getValue(aJson, aPath)) )
				{
					this.setValue(aResult, aPath, aValue);
				}
			}
			else
			{
				crossLinks.put(aPath, aValue);
			}
			return true;
		});

		this.jsonPathEvaluator(aJson, function(aPath, aValue, aType)
		{
			if (!pathSet.isContains(aPath))
			{
				if (aType !== Jsoner.JSON_NODE_CROSS_LINKED)
				{
					var value = this.getValue(aTemplate, aPath);
					if ( !this.isEquals(aValue, value) ) 
					{
						var obj = parsePath(aPath);
						if ( !COMMONS.isString(obj) )
						{
							var path;
							for( var i = 0; i < obj.index; i++ )
							{
								path = obj.path + "[" + i + "]." + obj.property;
								this.setValue(aResult, path, this.getValue(aTemplate, path) );
							}
						}
						this.setValue(aResult, aPath, value);
					}
				}
				else
				if ( this.isEquals(aValue, crossLinks.get(aPath)) )
				{
					crossLinks.remove(aPath);
				}
			}
			return true;
		});

		if ( !crossLinks.isEmpty() )
		{
      for( var name in crossLinks.fObject )
      {
	      if ( crossLinks.fObject.hasOwnProperty(name) )
	      {
	        this.setValue(aResult, name, crossLinks.fObject[name] );
		    }
      }
		}
	};

	var result = aTemplate;
	if ( COMMONS.isObject(aTemplate) && COMMONS.isObject(aJson) )
	{
		result = this.createNewInstance(aTemplate);
	  doDifference.call(this, aTemplate, aJson, result);
	}
	return result;
};

/**
  * Returns the map created by array of JSON objects using path for key and path for value.
  * @return {Map} Returns the map.
  *
  * @param {Array} The array of JSON objects.
  * @param {String} The path defined a way to compute a key with the value associated.
  * @param {String} The path defined a way to compute a value associated with key.
  */
Jsoner.prototype.jsonToMap = function(anArray, aPathToKey, aPathToValue)
{
	var result = {};
	if ( COMMONS.isArray(anArray) )
	{
		var key;
		for(var i = 0; i < anArray.length; i++ )
		{
		  key = this.getValue(anArray[i], aPathToKey);
			if ( COMMONS.isDefined(key) )
			{
				result[key] = this.getValue(anArray[i], aPathToValue);
			}
		}
	}
	else
	{
		this.fLogger.error( "jsonToMap, unsupported data type, array required: " + anArray );
	}
	return result;
};

/**************************************************************************/

/**
  * Visits all accepted JSON nodes until a visitor returns true, otherwise stop processing.
  * @param {JSON} The JSON objects.
  * @param {Function} The acceptor function that indicates that JSON node should be visited.
  * <ul>
  * <span>List of arguments passed to the acceptor:</span>
  *  <li> The path in JSON model.
  *  <li> The value of JSON node.
  *  <li> The collection of node attributes as pair name-value <samp>{"name":name, "value":value}</samp>.
  *  <li> The JSON node level.
  *  <li> The JSON node index within a parent node.</li>
  * <span>Returns true if visit to node accepted.</span>
  * </ul>
  *
  * @param {Function} The visitor.
  * <ul>
  * <span>List of arguments passed to the visitor:</span>
  *  <li> The path in JSON model as array.
  *  <li> The value of JSON node.
  *  <li> The collection of node attributes as pair name-value <samp>{"name":name, "value":value}</samp>.</li>
  * <span>Returns false if traverce of JSON should be aborted, otherwise returns true.</span>
  * </ul>
  */
Jsoner.prototype.visit = function(aJson, anAcceptor, aVisitor)
{
	this.jsonTreeWalker(aJson, function(aPath, aValue, anAttributes, aType)
	{
		var result = true;
		if (aType === Jsoner.JSON_NODE_START || aType === Jsoner.JSON_NODE_LEAF || aType === Jsoner.JSON_ATTRIBUTE)
		{
			if (anAcceptor.call(this, aPath, aValue, anAttributes))
			{
				result = aVisitor.call(this, aPath, aValue, anAttributes);
			}
		}
		return result;
	});
};

/**
  * Default acceptor, suitable for base lookup patterns.
  *
  * @return {Boolean} Returns true if visit node is accepted.
  *
  * @param {Array} The path in JSON model as array.
  * @param The value of JSON node.
  * @param The path pattern.
  *  <ul>
  *   <span>Available types of pattern: </span>
  *   <li> A string with wildcard asterisk (*), that substituted for any characters in a path.
  *   <li> A string without wildcard that matched to equals.
  *   <li> A RegExp pattern.
  *  </ul>
  *
  *  <ul>
  *   <span>Limitation: only one asterisk supported.</span>
  *   <li> The path started with asterisk (*) represents end part of the path.
  *   <li> The path end of asterisk (*) represents first part of the path.
  *   <li> The path contains asterisk (*) in the middle of text represents first and end paths of the path.
  *  </ul>
  *
  * @param {Map} The value pattern to match node attributes and nested nodes attributes.
  *  Pattern represented as a map, contains pairs of nested property or attribute name and
  *  matched value or RegExp pattern.
  *  The value pattern looks like { "relativePath": value or RegExp, "relativePath": value or RegExp }.
  */
Jsoner.prototype.defaultAcceptor = function(aPath, aJson, aPathPattern, aValuePattern)
{
	var result = true;
	if ( COMMONS.isDefined(aPathPattern) )
	{
		var path = aPath.join('.');
		result = this.isMatch(aPathPattern, path);
	}
	if ( result && COMMONS.isDefined(aValuePattern) )
	{
		var value;
		var pattern;
		for (var name in aValuePattern)
		{
			value = this.getValue(aJson, name);
			pattern = aValuePattern[name];
			if ( COMMONS.isRegExp(pattern) )
			{
		    result = pattern.test( "" + value );
			}
			else
			{
				result = (pattern === value);
			}
			if ( !result )
			{
				break;
			}
		}
	}
	return result;
};

/**
  * Looks up all reasonable nodes by specified criteria.
  * @return {Array} Returns collection of reasonable nodes.
  *
  * @param {JSON} The JSON objects.
  * @param {String} The path pattern used to accept position in JSON object.
  *  <ul>
  *   <span>Available types of pattern: </span>
  *   <li> A string with wildcard asterisk (*), that substitutes any characters in a path.
  *   <li> A string without wildcard that matched to equals.
  *   <li> A RegExp pattern.
  *  </ul>
  *
  * @param {Map} The value pattern used to match node attributes and nested nodes attributes.
  * Pattern, which is represented as a map, contains pairs of nested property or attribute name and
  * matched value or RegExp pattern.
  * The value pattern looks like <samp>{"relativePath":RegExp, "relativePath":pattern}</samp>
  *
  * @see #DEFAULT_ACCEPTOR
  */
Jsoner.prototype.lookupAll = function(aJson, aPathPattern, aValuePattern)
{
	var result = [];
	this.visit(aJson, function(aPath, aValue, anAttributes)
	{
		return this.defaultAcceptor.call(this, aPath, aValue, aPathPattern, aValuePattern);
	}, function(aPath, aValue)
	{
		result.push(aValue);
		return true;
	});
	return result;
};

/**
  * Looks up first reasonable node by specified criteria.
  * @return Returns the first matched node.
  *
  * @param {JSON} The JSON objects.
  * @param {String} The path pattern used to accept position in JSON object.
  *  <ul>
  *   <span>Available types of pattern: </span>
  *   <li> A string with wildcard asterisk (*), that substitutes any characters in a path.
  *   <li> A string without wildcard that matches equals.
  *   <li> A RegExp pattern.
  *  </ul>
  *
  * @param {Map} The value pattern to unite corresponding node attributes and nested nodes attributes.
  * Pattern represented as a map, contains pairs of nested property or attribute name and
  * matched value or RegExp pattern.
  * The value pattern looks like <samp>{"relativePath":RegExp, "relativePath":pattern}</samp>
  *
  * @see #DEFAULT_ACCEPTOR
  */
Jsoner.prototype.lookupFirst = function(aJson, aPathPattern, aValuePattern)
{
	var result = null;
	this.visit(aJson, function(aPath, aValue, anAttributes)
	{
		return this.defaultAcceptor(aPath, aValue, aPathPattern, aValuePattern);
	}, function(aPath, aValue)
	{
		result = aValue;
		return false;
	});
	return result;
};

/**
  * Indicates that reasonable node is found by specified criteria.
  * @return {Boolean} Returns true if at least one node is found, otherwise - false.
  *
  * @param {JSON} The JSON objects.
  * @param {String} The path pattern used to accept position in JSON object.
  *  <ul>
  *   <span>Available types of pattern: </span>
  *   <li> A string with wildcard asterisk (*), that substitute any characters in a path.
  *   <li> A string without wildcard that matches equals.
  *   <li> A RegExp pattern.
  *  </ul>
  *
  * @param {Map} The value pattern used to unite coresponding node attributes and nested nodes attributes.
  * Pattern represented as a map, contains pairs of nested property or attribute name and
  * matched value or RegExp pattern.
  * The value pattern looks like <samp>{"relativePath":RegExp, "relativePath":pattern}</samp>
  *
  * @see #DEFAULT_ACCEPTOR
  */
Jsoner.prototype.isContains = function(aJson, aPathPattern, aValuePattern)
{
	var result = this.lookupFirst(aJson, aPathPattern, aValuePattern);
	return (result !== null);
};

/**
  * Returns amount of reasonable nodes by specified criteria.
  * @return {Number} Returns count of reasonable nodes by specified criteria
  *
  * @param {JSON} The JSON objects.
  * @param {String} The path pattern used to accept position in JSON object.
  *  <ul>
  *   <span>Available types of pattern: </span>
  *   <li> A string with wildcard asterisk (*), that substitutes any characters in a path.
  *   <li> A string without wildcard that matched to equals.
  *   <li> A RegExp pattern.
  *  </ul>
  *
  * @param {Map} The value pattern used to match node attributes and nested nodes attributes.
  * Pattern represented as a map, contains pairs of nested property or attribute name and
  * matches value or RegExp pattern.
  * The value pattern looks like <samp>{"relativePath":RegExp, "relativePath":pattern}</samp>
  *
  * @see #DEFAULT_ACCEPTOR
  */
Jsoner.prototype.getCount = function(aJson, aPathPattern, aValuePattern)
{
	var result = 0;
	this.visit(aJson, function(aPath, aValue, anAttributes)
	{
		return this.defaultAcceptor(aPath, aValue, aPathPattern, aValuePattern);
	}, function(aPath, aValue)
	{
		result++;
		return true;
	});
	return result;
};

/**************************************************************************/

/**
  * Returns an array of the attributes on the JSON node.
  * @return {Array} Returns an array of the attributes on the JSON node
  *
  * @param {JSON} The JSON objects.
  * @param {String} The path defines a way to node in JSON.
  *
  * @see #isAttribute
  */
Jsoner.prototype.getAttributes = function(aJson, aPath)
{
  var value = this.getValue(aJson, aPath);
	var result = this.collectAttributes(aPath, value, aJson);
	return result;
};

/**
  * Returns an array of the child nodes on the JSON node.
  * @return {Array} Returns an array of the child nodes on the JSON node.
  *
  * @param {JSON} The JSON objects.
  * @param {String} The path defines a way to node in JSON.
  *
  * @see #isAttribute
  */
Jsoner.prototype.getChildren = function(aJson, aPath)
{
	var result = [];
  var obj = this.getValue(aJson, aPath);
	if ( COMMONS.isDefined(obj) )
	{
		result = this.collectChildren(aPath, obj, aJson);
	}
	return result;
};

/**
  * Indicates that a node is leaf.
  * @return {Boolean} Returns true if so, otherwise - false.
  *
  * @param {JSON} The JSON objects.
  * @param {String} The path defines a way to node in JSON.
  *
  * @see #getChildren
  */
Jsoner.prototype.isLeaf = function(aJson, aPath)
{
	var children = this.getChildren(aJson, aPath);
	return children.length === 0;
};

/**
  * Returns the first child of the JSON node.
  * @return Returns the first child of the JSON node.
  * If the node is leaf or path is wrong returns undefined.
  *
  * @param {JSON} The JSON objects.
  * @param {String} The path defines a way to node in JSON.
  */
Jsoner.prototype.getFirstChild = function(aJson, aPath)
{
	var children = this.getChildren(aJson, aPath);
	var result = children.length > 0 ? children[0] : undefined
	return result;
};

/**
  * Returns the last child of the JSON node.
  * @return Returns the last child of the JSON node.
  * If the node is leaf or path is wrong returns undefined.
  *
  * @param {JSON} The JSON objects.
  * @param {JSON} The path defines a way to node in JSON.
  */
Jsoner.prototype.getLastChild = function(aJson, aPath)
{
	var children = this.getChildren(aJson, aPath);
	var result = children.length > 0 ? children[children.length - 1] : undefined
	return result;
};

/**
  * Inserts the specified value into the array of nodes on the JSON.
  *
  * @param {JSON} The JSON objects.
  * @param {String} The path defines a way to node in JSON.
  * @param  The value should be inserted.
  * @param {Integer} The position where the value should be inserted.
  *
  * @return {JSON} The modified JSON object, useful for making chank of changes.
  */
 Jsoner.prototype.addChild = function(aJson, aPath, aValue, aPosition)
{
	function parsePath(aPath)
  {
	  var result = aPath;
	  if ( aPath.charAt(aPath.length - 1) === ']' )
	  {
		  var index = aPath.lastIndexOf("[");
		  result = {path:aPath.substring(0, index),
			          index:aPath.substring(index + 1, aPath.length-1)};
		}
	  return result;
  }

	var obj = this.getValue(aJson, aPath);
	if ( COMMONS.isUndefined(aPosition) )
	{
		if ( COMMONS.isUndefined(obj) )
		{
			this.setValue(aJson, aPath, aValue );
		}
		else
		{
			if ( !COMMONS.isArray(obj) )
			{
			  obj = [obj];
				this.setValue(aJson, aPath, obj);
			}
		  obj.push(aValue);
		}
	}
	else
	{
		if ( COMMONS.isUndefined(obj) )
		{
			obj = [];
			this.setValue(aJson, aPath, obj );
		}
		else
		{
			if ( !COMMONS.isArray(obj) )
			{
			  obj = [obj];
				this.setValue(aJson, aPath, obj);
			}
			if ( aPosition < obj.length )
			{
				for (var i = obj.length - 1; i >= aPosition; i--)
				{
					obj[i + 1] = obj[i];
				}
			}
			obj[aPosition] = aValue;
		}
	}
	return aJson;
};

/**
 * Removes all children nodes from the specified by path node.
 *
 * @param {JSON} The JSON objects.
 * @param {String} The path defines a way to node in JSON.
 *
 * @return {JSON} The modified JSON object, useful to make chank of changes.
 */
Jsoner.prototype.removeChildren = function(aJson, aPath)
{
	var obj = this.getValue(aJson, aPath);
	if ( !COMMONS.isUndefined(obj) )
	{
		this.setValue(aJson, aPath, undefined);
		delete aJson[aPath];
	}
	return aJson;
};

/**
 * Removes the child node from the specified by path node.
 *
 * @param {JSON} The JSON objects.
 * @param {String} The path defines a way to node in JSON.
 * @param {JSON} The child node should be removed.
 *
 * @return {JSON} The modified JSON object, useful to make chank of changes.
 */
Jsoner.prototype.removeChild = function(aJson, aPath, aValue)
{
  var obj = this.getValue(aJson, aPath);
	if ( !COMMONS.isUndefined(obj) )
	{
		if ( COMMONS.isArray(obj) )
		{
			var index = -1;
			for( var i = 0; i < obj.length; i++)
			{
				var value = obj[i];
				if ( value === aValue )
				{
					index = i;
					break;
				}
			}

			if ( index !== -1 )
			{
				for (var i = index; i < obj.length - 1; i++)
				{
					obj[i] = obj[i + 1];
				}
				obj.length = obj.length - 1;
			}
		}
		else
		if ( this.isEquals(obj, aValue) )
		{
			this.setValue(aJson, aPath, undefined);
			delete aJson[aPath];
		}
	}
	return aJson;
};

/**************************************************************************/

/**
  * Emulates path-value events for HTML form.
  *
  * @param {Form} The HTML form.
  * @param {Function} The observer, called  to process when the form element received.
  *
  * <ul>
  * <span>List of arguments passed to the callBack function:</span>
  *  <li>The HTML form element name.
  *  <li>The HTML form element.
  * </ul>
  */
Jsoner.prototype.htmlFormEvaluator = function(aForm, aCallBack)
{
	if ( COMMONS.isDefined(aForm) )
	{
		for (var i = 0; i < aForm.elements.length; i++)
		{
			var element = aForm.elements[i];
			if ( element.name )
			{
				aCallBack.call(this, element.name, element);
			}
		}
	}
};

/**
  * Utility method, sets value to HTML form field.
  * Assigns the value to HTML form field "value" property by defaults,
  * sets select index for "select" element and
  * sets checked to "checkbox" or "radio group".
  *
  * @param {Element} The HTML form field.
  * @param The value.
  */
Jsoner.prototype.setFieldValue = function(aElement, aValue)
{
	if ( COMMONS.isObject(aElement) )
	{
		if ( typeof(aElement) === "select" )
		{
			for (var i = 0; i < aElement.options.length; i++)
			{
				var option = aElement.options[i];
				if (option.value === aValue)
				{
					aElement.selectedIndex = i;
					option.selected = true;
				}
				else
				{
					option.removeAttribute("selected");
				}
			}
		}
		else
		if ( aElement.type === "checkbox" || aElement.type === "radio" )
		{
			aElement.checked = (aElement.value === ("" + aValue));
		}
		else
		{
			aElement.value = COMMONS.isDefined(aValue) ? aValue : '';
		}
	}	
};

/**
  * Utility method, returns HTML form field value.
  * Captures the "value" property of the HTML form field by defaults,
  * gets option value for "select" element, gets "checkbox" or "radio group" value if
  * the ones is checked.
  * @return {String} Returns the HTML form field value.
  *
  * @param {Element} The HTML form field.
  */
Jsoner.prototype.getFieldValue = function(aElement)
{
	var result = undefined;
	if ( COMMONS.isObject(aElement) )
	{
		if ( typeof(aElement) === "select" )
		{
			result = aElement.options[aElement.selectedIndex].value;
		}
		else
		if ( aElement.type === "checkbox")
		{
			result = aElement.checked ? aElement.value : false;
		}
		else
		if (aElement.type === "radio")
		{
			if ( aElement.checked )
			{
				result = aElement.value;
			}
		}
		else
		{
			result = aElement.value;
		}
	}
	return result;
};

/**
  * Populates JSON data to HTML form.
  *
  * @param {JSON} The JSON object.
  * @param {Form} The HTML form.
  *
  * @param {Map} Function or Map, which converts the HTML form element name into JSON path.
  * <ul>
  *  <span>List of arguments,which is passed to the converter in case of a function:</span>
  *   <li> The HTML form element name.
  *   <li> The HTML form element.</li>
  *  <span>Converter returns corresponding JSON path.</span>
  * </ul>
  */
Jsoner.prototype.populateJsonToForm = function(aJson, aForm, aConvertor)
{
	if ( COMMONS.isDefined(aForm) && COMMONS.isDefined(aJson) )
	{
		var convertor = this.converterFactory(aConvertor);

		this.htmlFormEvaluator(aForm, function(aElementName, aElement)
		{
			 var path = convertor.call(this, aElementName, aElement);
			 if ( COMMONS.isString(path) )
			 {
		     var value = this.getValue(aJson, path);
				 if ( this.getFieldValue(aElement) !== value )
				 {
					 this.setFieldValue(aElement, value ? value : '');
					 if ( COMMONS.isFunction(aElement.onchange) )
					 {
						 aElement.onchange.call(aElement);
					 }
					 else
					 if ( COMMONS.isFunction(aElement.onclick) )
					 {
						 aElement.onclick.call(aElement);
					 }
				 }
			 }
		});
	}
};

/**
  * By default, converts HTML form element name to JSON path.
  *
  * @param {String} The HTML form element name.
  * @param {Element} The HTML form element.
  *
  * @return {String} Returns element name in case when element is not
  * disabled and is not read only, otherwise returns null.
  *
  */
Jsoner.prototype.defaultHtmlConverter = function(aElementName, aElement)
{
	var result = aElementName;
	if ( COMMONS.toBoolean(aElement.readOnly) || COMMONS.toBoolean(aElement.disabled) )
	{
		result = null;
	}
	return result;
};

/**
  * Populates HTML form data to JSON object.
  *
  * @param {Form} The HTML form.
  * @param {JSON} The JSON object.
  *
  * @param {Map} The HTML form element name to JSON path converter as function or Map.
  * <ul>
  *  <span>List of arguments passed to the converter in case of a function:</span>
  *   <li> The HTML form element name.
  *   <li> The HTML form element.</li>
  *  <span>Converter returns corresponding JSON path.</span>
  * </ul>
  *
  * @return {JSON} The modified JSON object, useful to make chank of changes.
  */
Jsoner.prototype.populateFormToJson = function(aForm, aJson, aConverter)
{
	var result = aJson;
	var pathSet = new KeySet();

	if ( COMMONS.isObject(aForm) )
	{
		var converter = this.converterFactory(aConverter || this.defaultHtmlConverter);

		this.htmlFormEvaluator(aForm, function(aElementName, aElement)
		{
		   var path = converter.call(this, aElementName, aElement);
			 if ( COMMONS.isString(path))
			 {
				 var value = this.getFieldValue(aElement);
				 if ( COMMONS.isDefined(value) )
				 {
					 var oldValue = this.getValue(result, path);
					 if ( COMMONS.isNumber(oldValue) )
					 {
						 value = COMMONS.toFloat(value);
					 }
					 else
					 if ( COMMONS.isBoolean(oldValue) )
					 {
						 value = COMMONS.toBoolean(value);
					 }
					 this.populate(result, path, value, true);
				}
			 }
		});
	}
	return result;
};

/********************************************************/

/**
  * Predefined JSON pattern key for CDATA.
  * @type string
  * @final
  */
Jsoner.prototype.PATTERN_CDATA_KEY = "CDATA";

/**
  * Predefined default JSON pattern.
  * @type string
  * @final
  */
Jsoner.prototype.PATTERN_DEFAULT_KEY = "default";

/**
  * Predefined selective JSON pattern resolver.
  * Pattern - it's a specified data,
  * that define how JSON node will be transformed to HTML DOM node.
  *
  * <ul>
  *  <span>Following rules are used to obtain the pattern: </span>
  *   <li> Searches pattern by path.
  *   <li> Searches pattern by type.
  *   <li> Gets default pattern.</li>
  *  <span>Returns the first corresponding pattern.</span>
  * </ul>
  *
  * @param {Map} The object, contains collection of patterns.
  * @param {Sting} The path in JSON model, used to resolve pattern.
  * @param The value of JSON property, used to resolve pattern.
  *
  * @return {JSON} Returns the JSON representation of pattern used to prepare HTML DOM node.
  *
  * @see #jsonToHTML
  */
Jsoner.prototype.selectPatternResolver = function(aJson, aPath, aValue)
{
	var result = this.getValue(aJson, aPath);
	if ( COMMONS.isUndefined(result) )
	{
		var index = aPath.lastIndexOf('.');
		if ( index > 0 )
		{
			aPath = aPath.substring(index + 1);
		}
		if (this.isText(aPath) || this.isCDATA(aPath) )
		{
			result = this.getValue(aJson, this.PATTERN_CDATA_KEY);
		}
		if ( COMMONS.isUndefined(result) )
		{
			var type = typeof(aValue);
			result = this.getValue(aJson, type);
			if ( COMMONS.isUndefined(result) )
			{
				result = this.getValue(aJson, this.PATTERN_DEFAULT_KEY);
			}
		}
	}
	return this.clone(result);
};

/**
  * Predefined cascade JSON pattern resolver.
  * Pattern - it's a specified data,
  * that defines how JSON node will be transformed into DOM node.
  *
  * <ul>
  *  <span>Following rules are used to obtain the pattern: </span>
  *   <li> Gets default pattern.
  *   <li> Searches pattern by type.
  *   <li> Searches pattern by accumulated segments of path.
  *   <li> Searches pattern by path.</li>
  *  <span>Returns the  corresponding merged pattern.</span>
  * </ul>
  *
  * @param {Map} The object, contains collection of patterns.
  * @param {Sting} The path in JSON model, used to resolve pattern.
  * @param The value of JSON property, used to resolve pattern.
  *
  * @return {JSON} Returns the JSON representation of pattern used to prepare HTML DOM node.
  *
  * @see #jsonToHTML.
  */
Jsoner.prototype.cascadePatternResolver = function(aJson, aPath, aValue)
{
	var result = this.merge(this.getValue(aJson, this.PATTERN_DEFAULT_KEY),
													this.getValue(aJson, typeof(aValue)), true);

	var index = aPath.lastIndexOf('.');
	if ( index > 0 )
	{
		var name = aPath.substring(index + 1);
		if (this.isText(name) || this.isCDATA(name) )
		{
			result = this.merge(result, this.getValue(aJson, this.PATTERN_CDATA_KEY), true);
		}
	}
	var key = [];
	var path = aPath.split('.');
	for( var i = 0; i < path.length; i++ )
	{
		key.push( path[i] );
		result = this.merge(result, this.getValue(aJson, key.join('.')), true);
	}
	return result;
};

/**
  * Creates HTML DOM structure based on JSON object and pattern.
  *
  * @param {JSON} The JSON object.
  * @param The collection of patterns.
  *
  * @param {Function} The pattern resolver, used to obtain corresponding pattern.
  * it is pattern resolver, that encapsulates a logic of obtaining  pattern .
  * <ul>
  *  <span>List of arguments passed to the pattern resolver:</span>
	*   <li> The collection of patterns.
  *   <li> The path in JSON model.
  *   <li> The value of JSON property associated with the path.</li>
  *   <span> Resolver returns corresponding pattern to process JSON node or null to skip ones.</span>
  * </ul>
  *
  * @param {Function} The parent node provider or the HTML node used to add child to them.
  * Parent node provider encapsulate a layout logic.
  * <ul>
  *  <span> List of arguments passed to the provider in case of provider is a function: </span>
  *   <li>The path in JSON model.
  *   <li>The value of JSON property.</li>
  *   <span>Returns HTML node or null to skip add child operation.</span>
  * </ul>
  *
  * @param {Function} The HTML node factory.
  * The factory creates HTML DOM node or array of nodes that should be appended to parent node.
  * <ul>
  *  <span> List of arguments passed to the factory: </span>
	*   <li> The pattern.
	*   <li> The owner document.
  *   <li> The path in JSON model.
  *   <li> The value of JSON property associated with the path.</li>
  *   <span>Returns HTML DOM node or array of nodes to append to parent node or null to skip add child operation.</span>
  * </ul>
  */
Jsoner.prototype.jsonToHTML = function(aJson, aPattern, aPatternResolver, aParentNodeProvider, aNodeFactory)
{
  var patternResolver = aPatternResolver || this.cascadePatternResolver;
	var nodeFactory = aNodeFactory || this.jsonToDOM;
	var parentNodeProvider = COMMONS.isFunction(aParentNodeProvider) ? aParentNodeProvider : function() {return aParentNodeProvider;};

	this.jsonPathEvaluator(aJson, function(aName, aValue)
  {
		var pattern = patternResolver.call(this, aPattern, aName, aValue);
	  if ( COMMONS.isDefined(pattern) )
	  {
		  var parent = parentNodeProvider.call(this, aName, aValue);
			if ( COMMONS.isObject(parent) )
			{
				var node = nodeFactory.call(this, pattern, parent.ownerDocument || document, aName, aValue); 
				if ( COMMONS.isObject(node) )
				{
					if ( COMMONS.isArray(node) )
					{
						for( var i = 0; i < node.length; i++ )
						{
							parent.appendChild(node[i]);
						}
					}
					else
					{
						parent.appendChild(node);
					}
				}
			}
	  }
	  return true;
  });
};

/**
  * Creates HTML node or array of HTML nodes by JSON object
  *
  * @param {JSON} The JSON representation of HTML node.
  *
  * @param {Function} The node name converter as function or Map.
  * <ul>
  *  <span>List of arguments passed to the converter in case of a function:</span>
  *   <li> The JSON node name.
  *   <li> The JSON path as array.
  *   <li> The JSON node value.</li>
  *  <span>Returns string representation of HTML node name to process or null to skip processing.</span>
  * </ul>
  * @param {Document} The owner document.
  *
  * @param {Function} The attribute name converter as function or Map.
  * <ul>
	*  <span>List of arguments passed to the converter in case when converter is a function:</span>
  *   <li> The attribute name.
  *   <li> The attribute value.
  *   <li> The JSON path as array.</li>
  *  <span> Returns string presentation of HTML node attribute name. </span>
  * </ul>
  *
  * @throw Exception
  * The jsonToDOM can raise exception in case when impossible operation happens.
  */
Jsoner.prototype.jsonToDOM = function(aJson, aDocument, aNodeConverter, anAttributeConverter )
{
	var result = null;
	var parent = null;
	var level = 0;

	var nodeConverter = this.converterFactory(aNodeConverter);
	var attributeConverter = this.converterFactory(anAttributeConverter);

	this.jsonTreeWalker(aJson, function(aPath, aValue, anAttributes, aType, aLevel)
	{
		var element = null;
		if (aType === Jsoner.JSON_NODE_START || aType === Jsoner.JSON_NODE_LEAF || aType === Jsoner.JSON_ATTRIBUTE)
		{
			var nodeName = nodeConverter.call(this, this.getLastProperty(aPath), aValue);
			if (COMMONS.isString(nodeName))
			{
				element = aDocument.createElement(nodeName);
				if (aType === Jsoner.JSON_ATTRIBUTE)
				{
					element.appendChild(aDocument.createTextNode(aValue));
				}
				if (COMMONS.isArray(anAttributes))
				{
					for (var i = 0; i < anAttributes.length; i++)
					{
						var attribute = anAttributes[i];
						var name = attributeConverter.call(this, attribute.name, attribute.value, aPath);
						if (COMMONS.isDefined(name))
						{
							var value = attribute.value;
							if (this.isText(name) || this.isCDATA(name))
							{
								element.appendChild(aDocument.createTextNode(value));
							}
							else
							{
								if (name === "class")
								{
									element.className = value;
								}
								else
								if (COMMONS.isIE && (name.indexOf("on") === 0))
								{
									element.attachEvent(name, new Function('', value));
								}
								else
								if (COMMONS.isIE && name === "style")
								{
									element.style.cssText = value;
								}
								else
								{
									element.setAttribute(name, value);
								}
							}
						}
					}
				}

				if (aLevel === 0)
				{
					result = result ? [result] : element;
					if (COMMONS.isArray(result))
					{
						result.push(element);
					}
				}
				else
				{
					while (level >= aLevel)
					{
						parent = parent.parentNode;
						level--;
					}
					if ((aPath === "tr" || aPath === "TR") && parent.nodeName === 'TABLE')
					{
						var tbody = aDocument.createElement("tbody");
						parent.appendChild(tbody);
						parent = tbody;
					}
					parent.appendChild(element);
				}
				parent = element;
				level = aLevel;
			}
		}
		return true;
	});

	return result;
};